home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / mpeg_decode.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-26  |  69.6 KB  |  2,765 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. //
  18. ///////////////////////////////////////////////////////////////////////////
  19. //
  20. //                                 WARNING
  21. //
  22. // This code is heavily based off of the Java MPEG video player written by
  23. // Joerg Anders.  Because his code was released under the GNU GPL v2, this
  24. // means VirtualDub must also be released under GNU GPL v2 when MPEG
  25. // support is included.
  26. //
  27. // (Like that's any different.)
  28. //
  29. // This code is really nasty...
  30. //
  31. ///////////////////////////////////////////////////////////////////////////
  32.  
  33. #include <stdio.h>
  34. #include <process.h>
  35. #include <crtdbg.h>
  36. #include <assert.h>
  37.  
  38. #include <windows.h>
  39. #include <math.h>
  40.  
  41. #include "CMemoryBitInput.h"
  42. #include "Error.h"
  43.  
  44. #include "cpuaccel.h"
  45. #include "mpeg_idct.h"
  46. #include "mpeg_tables.h"
  47. #include "mpeg_decode.h"
  48.  
  49. //////////////////////////////////////////////////////////////
  50.  
  51. #ifdef _DEBUG
  52. //#define STATISTICS
  53. #endif
  54.  
  55. #define DCT_POSITION_CHECKING
  56.  
  57. //#define MB_STATS
  58. //#define MB_SPLIT_STATS
  59.  
  60. //#define TIME_TRIALS
  61.  
  62. //#define NO_DECODING
  63.  
  64. //#define DISPLAY_INTER_COUNT
  65.  
  66. //////////////////////////////////////////////////////////////
  67.  
  68. #define VIDPKT_TYPE_PICTURE_START        (0x00)
  69. #define VIDPKT_TYPE_SLICE_START_MIN        (0x01)
  70. #define    VIDPKT_TYPE_SLICE_START_MAX        (0xaf)
  71.  
  72. #define MIDVAL (262144)
  73. #define ROUNDVAL (1024)
  74.  
  75. #ifdef _DEBUG
  76. class BranchPredictor {
  77. private:
  78.     int v[16];
  79.     int ls;
  80.     int taken;
  81.     int mispredict;
  82.     int total;
  83.     const char *s;
  84.  
  85. public:
  86.     BranchPredictor(const char *_s);
  87.     ~BranchPredictor();
  88.  
  89.     bool predict(bool b);
  90. };
  91.  
  92. BranchPredictor::BranchPredictor(const char *_s) {
  93.     memset(v, 0, sizeof v);
  94.     ls = 0;
  95.     taken = 0;
  96.     mispredict = 0;
  97.     total = 0;
  98.     s = _s;
  99. }
  100.  
  101. BranchPredictor::~BranchPredictor() {
  102.     char buf[256];
  103.  
  104.     sprintf(buf, "Branch predictor \"%s\": %d branches (%d%% taken), %d mispredicts (%d%%)\n"
  105.             ,s
  106.             ,total
  107.             ,MulDiv(taken, 100, total)
  108.             ,mispredict
  109.             ,MulDiv(mispredict, 100, total));
  110.     _RPT0(0,buf);
  111. }
  112.  
  113. bool BranchPredictor::predict(bool b) {
  114.  
  115.     if (b) {
  116.         if (v[ls]<2)
  117.             ++mispredict;
  118.         if (v[ls]<3)
  119.             ++v[ls];
  120.         ++taken;
  121.     } else {
  122.         if (v[ls]>=2)
  123.             ++mispredict;
  124.         if (v[ls])
  125.             --v[ls];
  126.     }
  127.  
  128.     ls = ((ls<<1)|(int)b) & 15;
  129.     ++total;
  130.  
  131.     return b;
  132. }
  133.  
  134. BranchPredictor g_predict080(">=080 (90%)");
  135. BranchPredictor g_predict600("<600 (40%)");
  136. BranchPredictor g_predictC00("C00-FFF (20%)");
  137. BranchPredictor g_predict800("800-BFF");
  138. BranchPredictor g_predict040("040");
  139. BranchPredictor g_predict020("020");
  140.  
  141. #define PREDICT(ths, v) (g_predict##ths.predict(v))
  142. #else
  143. #define PREDICT(ths, v) (v)
  144. #endif
  145.  
  146.  
  147. //////////////////////////////////////////////////////////////
  148.  
  149. typedef unsigned char YUVPixel;
  150.  
  151. static void video_process_picture_start_packet(char *ptr);
  152. static void video_process_picture_slice(char *ptr, int type);
  153.  
  154. static void YUVToRGB32(YUVPixel *Y_ptr, YUVPixel *U_ptr, YUVPixel *V_ptr, unsigned char *dst, long bpr, long w, long h);
  155. static void YUVToRGB24(YUVPixel *Y_ptr, YUVPixel *U_ptr, YUVPixel *V_ptr, unsigned char *dst, long bpr, long w, long h);
  156. static void YUVToRGB16(YUVPixel *Y_ptr, YUVPixel *U_ptr, YUVPixel *V_ptr, unsigned char *dst, long bpr, long w, long h);
  157. static void YUVToUYVY16(YUVPixel *Y_ptr, YUVPixel *U_ptr, YUVPixel *V_ptr, unsigned char *dst, long bpr, long w, long h);
  158. static void YUVToYUY216(YUVPixel *Y_ptr, YUVPixel *U_ptr, YUVPixel *V_ptr, unsigned char *dst, long bpr, long w, long h);
  159. static void YUVToYUV12(YUVPixel *Y_ptr, YUVPixel *U_ptr, YUVPixel *V_ptr, unsigned char *dst, long bpr, long w, long h);
  160.  
  161. static void video_copy_forward(int x_pos, int y_pos);
  162. static void video_copy_forward_prediction(int x_pos, int y_pos, bool);
  163. static void video_copy_backward_prediction(int x_pos, int y_pos, bool);
  164. static void video_add_backward_prediction(int x_pos, int y_pos, bool);
  165.  
  166. ///////////////////////////////////////////////////////////////////////////////
  167.  
  168. static const int zigzag[] = {        // the reverse zigzag scan order
  169.      0,  1,  8, 16,  9,  2,  3, 10,
  170.     17, 24, 32, 25, 18, 11,  4,  5,
  171.     12, 19, 26, 33, 40, 48, 41, 34,
  172.     27, 20, 13,  6,  7, 14, 21, 28,
  173.     35, 42, 49, 56, 57, 50, 43, 36,
  174.     29, 22, 15, 23, 30, 37, 44, 51,
  175.     58, 59, 52, 45, 38, 31, 39, 46,
  176.     53, 60, 61, 54, 47, 55, 62, 63,
  177. };
  178.  
  179. static const int zigzag_MMX[] = {
  180.      0,  2,  8, 16, 10,  4,  6, 12, 
  181.     18, 24, 32, 26, 20, 14,  1,  3, 
  182.      9, 22, 28, 34, 40, 48, 42, 36, 
  183.     30, 17, 11,  5,  7, 13, 19, 25, 
  184.     38, 44, 50, 56, 58, 52, 46, 33, 
  185.     27, 21, 15, 23, 29, 35, 41, 54, 
  186.     60, 62, 49, 43, 37, 31, 39, 45, 
  187.     51, 57, 59, 53, 47, 55, 61, 63, 
  188. };
  189.  
  190. static const int intramatrix_default[64] = {        // the default intramatrix
  191.      8, 16, 19, 22, 26, 27, 29, 34,
  192.     16, 16, 22, 24, 27, 29, 34, 37,
  193.     19, 22, 26, 27, 29, 34, 34, 38,
  194.     22, 22, 26, 27, 29, 34, 37, 40,
  195.     22, 26, 27, 29, 32, 35, 40, 48,
  196.     26, 27, 29, 32, 35, 40, 48, 58, 
  197.     26, 27, 29, 34, 38, 46, 56, 69,
  198.     27, 29, 35, 38, 46, 56, 69, 83};
  199.  
  200. static char *memblock = NULL;
  201.  
  202. static int intramatrix0[64];
  203. static int nonintramatrix0[64];
  204.  
  205. static int intramatrices[32][64];
  206. static int nonintramatrices[32][64];
  207.  
  208. static struct MPEGBuffer {
  209.     YUVPixel *Y;
  210.     YUVPixel *U;
  211.     YUVPixel *V;
  212.     int frame_num;
  213. } buffers[3];
  214.  
  215. #define I_FRAME        (0x1)
  216. #define P_FRAME        (0x2)
  217. #define B_FRAME        (0x3)
  218. #define D_FRAME        (0x4)
  219.  
  220. static int frame_type;
  221.  
  222. static YUVPixel *Y_back, *Y_forw, *Y_dest;
  223. static YUVPixel *U_back, *U_forw, *U_dest;
  224. static YUVPixel *V_back, *V_forw, *V_dest;
  225.  
  226. static long pelWidth, pelHeight, mbWidth, mbHeight;
  227.  
  228. static BOOL reset_flag;
  229.  
  230. static long y_pitch, uv_pitch;
  231. static long y_modulo, uv_modulo;
  232.  
  233. extern "C" const unsigned long YUV_Y_table[], YUV_U_table[], YUV_V_table[];
  234. extern "C" const unsigned char YUV_clip_table[];
  235.  
  236. #ifdef STATISTICS
  237. struct {
  238.     int coded_block_pattern;
  239. } stats;
  240. #endif
  241.  
  242. #ifdef TIME_TRIALS
  243. struct {
  244.     int counts[4];
  245.     __int64 cycles[4];
  246.     __int64 totalcycles;
  247.     int totalframes;
  248. } timetrials;
  249. #endif
  250.  
  251. static int vector_limit_x;
  252. static int vector_limit_y;
  253.  
  254. static enum {
  255.     MPEG_NOT_READY,
  256.         MPEG_READY_SCALAR,
  257.         MPEG_READY_MMX
  258. } mpeg_ready_state;
  259.  
  260. extern "C" void video_copy_prediction_Y_ISSE(YUVPixel *src, YUVPixel *dst, int vx, int vy, long pitch);
  261. extern "C" void video_copy_prediction_C_ISSE(YUVPixel *src, YUVPixel *dst, int vx, int vy, long pitch);
  262. extern "C" void video_add_prediction_Y_ISSE(YUVPixel *src, YUVPixel *dst, int vx, int vy, long pitch);
  263. extern "C" void video_add_prediction_C_ISSE(YUVPixel *src, YUVPixel *dst, int vx, int vy, long pitch);
  264. extern "C" void video_copy_prediction_Y_scalar(YUVPixel *src, YUVPixel *dst, int vx, int vy, long pitch);
  265. extern "C" void video_copy_prediction_C_scalar(YUVPixel *src, YUVPixel *dst, int vx, int vy, long pitch);
  266. extern "C" void video_add_prediction_Y_scalar(YUVPixel *src, YUVPixel *dst, int vx, int vy, long pitch);
  267. extern "C" void video_add_prediction_C_scalar(YUVPixel *src, YUVPixel *dst, int vx, int vy, long pitch);
  268. extern "C" void video_copy_prediction_Y_MMX(YUVPixel *src, YUVPixel *dst, int vx, int vy, long pitch);
  269. extern "C" void video_copy_prediction_C_MMX(YUVPixel *src, YUVPixel *dst, int vx, int vy, long pitch);
  270. extern "C" void video_add_prediction_Y_MMX(YUVPixel *src, YUVPixel *dst, int vx, int vy, long pitch);
  271. extern "C" void video_add_prediction_C_MMX(YUVPixel *src, YUVPixel *dst, int vx, int vy, long pitch);
  272.  
  273. static void (*video_copy_prediction_Y)(YUVPixel *src, YUVPixel *dst, int vx, int vy, long pitch);
  274. static void (*video_copy_prediction_C)(YUVPixel *src, YUVPixel *dst, int vx, int vy, long pitch);
  275. static void (*video_add_prediction_Y)(YUVPixel *src, YUVPixel *dst, int vx, int vy, long pitch);
  276. static void (*video_add_prediction_C)(YUVPixel *src, YUVPixel *dst, int vx, int vy, long pitch);
  277.  
  278. //int lpos_stats[64];
  279.  
  280. ////////////////////////////////////////////////////////////////////////////////
  281.  
  282. void mpeg_deinitialize() {
  283. //    if (memblock) { freemem(memblock); memblock = NULL; }
  284.     if (memblock) { VirtualFree(memblock, 0, MEM_RELEASE); memblock = NULL; }
  285. }
  286.  
  287. void mpeg_initialize(int width, int height, char *imatrix, char *nimatrix, BOOL fullpel_only) {
  288.     mpeg_deinitialize();
  289.  
  290.     try {
  291.         int i;
  292.  
  293.         pelWidth        = width;
  294.         pelHeight        = height;
  295.         mbWidth            = (width+15)/16;
  296.         mbHeight        = (height+15)/16;
  297.         y_pitch            = mbWidth * 16;
  298.         uv_pitch        = mbWidth * 8;
  299.         y_modulo        = 15*16*mbWidth;
  300.         uv_modulo        = 7*8*mbWidth;
  301.  
  302.         vector_limit_x    = (mbWidth-1) * 32;
  303.         vector_limit_y    = (mbHeight-1) * 32;
  304.  
  305. //        if (!(memblock = (char *)allocmem(32 + mbWidth * mbHeight * (3*256*sizeof(YUVPixel) + 6*64*sizeof(YUVPixel)) + (uv_pitch+8)*8)))
  306. //            throw MyMemoryError();
  307.  
  308.         if (!(memblock = (char *)VirtualAlloc(NULL, mbWidth * mbHeight * (3*256*sizeof(YUVPixel) + 6*64*sizeof(YUVPixel)) + (32)*8, MEM_COMMIT, PAGE_READWRITE)))
  309.             throw MyMemoryError();
  310.  
  311.         memset(memblock, 0, mbWidth * mbHeight * (3*256*sizeof(YUVPixel) + 6*64*sizeof(YUVPixel)) + (32)*8);
  312.  
  313.         buffers[0].Y    = (YUVPixel *)((char *)memblock ); //+ ((32-(long)memblock)&31));
  314.         buffers[1].Y    = (YUVPixel *)((char *)buffers[0].Y + mbWidth * mbHeight * 256 * sizeof(YUVPixel) + 32);
  315.         buffers[2].Y    = (YUVPixel *)((char *)buffers[1].Y + mbWidth * mbHeight * 256 * sizeof(YUVPixel) + 32);
  316.         buffers[0].U    = (YUVPixel *)((char *)buffers[2].Y + mbWidth * mbHeight * 256 * sizeof(YUVPixel) + 32);
  317.         buffers[1].U    = (YUVPixel *)((char *)buffers[0].U + mbWidth * mbHeight *  64 * sizeof(YUVPixel) + 32);
  318.         buffers[2].U    = (YUVPixel *)((char *)buffers[1].U + mbWidth * mbHeight *  64 * sizeof(YUVPixel) + 32);
  319.         buffers[0].V    = (YUVPixel *)((char *)buffers[2].U + mbWidth * mbHeight *  64 * sizeof(YUVPixel) + 32);
  320.         buffers[1].V    = (YUVPixel *)((char *)buffers[0].V + mbWidth * mbHeight *  64 * sizeof(YUVPixel) + 32);
  321.         buffers[2].V    = (YUVPixel *)((char *)buffers[1].V + mbWidth * mbHeight *  64 * sizeof(YUVPixel) + 32);
  322.  
  323.         buffers[0].frame_num = buffers[1].frame_num = buffers[2].frame_num = -1;
  324.  
  325.         if (imatrix)
  326.             for(i=0; i<64; i++) intramatrix0[zigzag[i]] = (unsigned char)imatrix[i];
  327.         else
  328.             memcpy(intramatrix0, intramatrix_default, 64*sizeof(int));
  329.  
  330.         if (nimatrix)
  331.             for(i=0; i<64; i++) nonintramatrix0[zigzag[i]] = (unsigned char)nimatrix[i];
  332.         else
  333.             for(i=0; i<64; i++) nonintramatrix0[i] = 16;
  334.  
  335.         IDCT_init();
  336.  
  337.         mpeg_reset();
  338.  
  339.     } catch(MyError e) {
  340.         mpeg_deinitialize();
  341.  
  342.         throw e;
  343.     }
  344. }
  345.  
  346. void mpeg_reset() {
  347.  
  348. //    for(int i=0; i<64; i++)
  349. //        _RPT2(0,"%d: %d\n", i, lpos_stats[i]);
  350.  
  351.     reset_flag = TRUE;
  352.     mpeg_ready_state = MPEG_NOT_READY;
  353. }
  354.  
  355. void mpeg_convert_frame32(void *output_buffer, int buffer_ID) {
  356. //    _RPT1(0,"MPEG: converting frame buffer %d\b", buffer_ID);
  357.  
  358. #ifdef NO_DECODING
  359.     return;
  360. #endif
  361.  
  362.  
  363. #ifdef _DEBUG
  364.     if (buffer_ID == -1) throw MyError("Invalid source buffer in "__FILE__", line %d",__LINE__);
  365. #endif
  366.  
  367. //    memset(buffers[buffer_ID].Y, 0x80, y_pitch*mbHeight*16);
  368.  
  369.     YUVToRGB32(buffers[buffer_ID].Y, buffers[buffer_ID].U, buffers[buffer_ID].V, (unsigned char *)output_buffer,
  370.             (mbWidth*16)*4, (pelWidth+1)>>1, (pelHeight+1)>>1);
  371. }
  372.  
  373. void mpeg_convert_frame24(void *output_buffer, int buffer_ID) {
  374. //    _RPT1(0,"MPEG: converting frame buffer %d\b", buffer_ID);
  375.  
  376. #ifdef NO_DECODING
  377.     return;
  378. #endif
  379.  
  380. #ifdef _DEBUG
  381.     if (buffer_ID == -1) throw MyError("Invalid source buffer in "__FILE__", line %d",__LINE__);
  382. #endif
  383.  
  384. //    memset(buffers[buffer_ID].Y, 0x80, y_pitch*mbHeight*16);
  385.  
  386.     YUVToRGB24(buffers[buffer_ID].Y, buffers[buffer_ID].U, buffers[buffer_ID].V, (unsigned char *)output_buffer,
  387.             (mbWidth*16)*3, ((pelWidth+7)&-8)>>1, (pelHeight+1)>>1);
  388. }
  389.  
  390. void mpeg_convert_frame16(void *output_buffer, int buffer_ID) {
  391. //    _RPT1(0,"MPEG: converting frame buffer %d\b", buffer_ID);
  392.  
  393. #ifdef NO_DECODING
  394.     return;
  395. #endif
  396.  
  397. #ifdef _DEBUG
  398.     if (buffer_ID == -1) throw MyError("Invalid source buffer in "__FILE__", line %d",__LINE__);
  399. #endif
  400.  
  401. //    memset(buffers[buffer_ID].Y, 0x80, y_pitch*mbHeight*16);
  402.  
  403.     YUVToRGB16(buffers[buffer_ID].Y, buffers[buffer_ID].U, buffers[buffer_ID].V, (unsigned char *)output_buffer,
  404.             (mbWidth*16)*2, ((pelWidth+7)&-8)>>1, (pelHeight+1)>>1);
  405. }
  406.  
  407. void mpeg_convert_frameUYVY16(void *output_buffer, int buffer_ID) {
  408. //    _RPT1(0,"MPEG: converting frame buffer %d\b", buffer_ID);
  409.  
  410. #ifdef NO_DECODING
  411.     return;
  412. #endif
  413.  
  414. #ifdef _DEBUG
  415.     if (buffer_ID == -1) throw MyError("Invalid source buffer in "__FILE__", line %d",__LINE__);
  416. #endif
  417.  
  418.     YUVToUYVY16(buffers[buffer_ID].Y, buffers[buffer_ID].U, buffers[buffer_ID].V, (unsigned char *)output_buffer,
  419.             (mbWidth*16)*2, (pelWidth+1)>>1, (pelHeight+1)>>1);
  420. }
  421.  
  422. void mpeg_convert_frameYUY216(void *output_buffer, int buffer_ID) {
  423. //    _RPT1(0,"MPEG: converting frame buffer %d\b", buffer_ID);
  424.  
  425. #ifdef NO_DECODING
  426.     return;
  427. #endif
  428.  
  429. #ifdef _DEBUG
  430.     if (buffer_ID == -1) throw MyError("Invalid source buffer in "__FILE__", line %d",__LINE__);
  431. #endif
  432.  
  433.     YUVToYUY216(buffers[buffer_ID].Y, buffers[buffer_ID].U, buffers[buffer_ID].V, (unsigned char *)output_buffer,
  434.             (mbWidth*16)*2, (pelWidth+1)>>1, (pelHeight+1)>>1);
  435. }
  436.  
  437. void mpeg_decode_frame(void *input_data, int len, int frame_num) {
  438.  
  439.  
  440. #ifdef NO_DECODING
  441.     return;
  442. #endif
  443.  
  444.     char *ptr = (char *)input_data;
  445.     char *limit = ptr + len - 4;
  446.     int type;
  447.  
  448.     if (MMX_enabled) {
  449.         if (ISSE_enabled) {
  450.             video_copy_prediction_Y = video_copy_prediction_Y_ISSE;
  451.             video_add_prediction_Y = video_add_prediction_Y_ISSE;
  452.             video_copy_prediction_C = video_copy_prediction_C_ISSE;
  453.             video_add_prediction_C = video_add_prediction_C_ISSE;
  454.         } else {
  455.             video_copy_prediction_Y = video_copy_prediction_Y_MMX;
  456.             video_add_prediction_Y = video_add_prediction_Y_MMX;
  457.             video_copy_prediction_C = video_copy_prediction_C_MMX;
  458.             video_add_prediction_C = video_add_prediction_C_MMX;
  459.         }
  460.     } else {
  461.         video_copy_prediction_Y = video_copy_prediction_Y_scalar;
  462.         video_add_prediction_Y = video_add_prediction_Y_scalar;
  463.         video_copy_prediction_C = video_copy_prediction_C_scalar;
  464.         video_add_prediction_C = video_add_prediction_C_scalar;
  465.     }
  466.  
  467.     if (MMX_enabled && mpeg_ready_state != MPEG_READY_MMX) {
  468.         int i,j;
  469.  
  470.         for(j=0; j<32; j++) {
  471.             for(i=0; i<64; i+=8) {
  472.                 nonintramatrices[j][i+0] = nonintramatrix0[i+0] * j;
  473.                 intramatrices   [j][i+0] = intramatrix0   [i+0] * j;
  474.                 nonintramatrices[j][i+2] = nonintramatrix0[i+1] * j;
  475.                 intramatrices   [j][i+2] = intramatrix0   [i+1] * j;
  476.                 nonintramatrices[j][i+4] = nonintramatrix0[i+2] * j;
  477.                 intramatrices   [j][i+4] = intramatrix0   [i+2] * j;
  478.                 nonintramatrices[j][i+6] = nonintramatrix0[i+3] * j;
  479.                 intramatrices   [j][i+6] = intramatrix0   [i+3] * j;
  480.                 nonintramatrices[j][i+1] = nonintramatrix0[i+4] * j;
  481.                 intramatrices   [j][i+1] = intramatrix0   [i+4] * j;
  482.                 nonintramatrices[j][i+3] = nonintramatrix0[i+5] * j;
  483.                 intramatrices   [j][i+3] = intramatrix0   [i+5] * j;
  484.                 nonintramatrices[j][i+5] = nonintramatrix0[i+6] * j;
  485.                 intramatrices   [j][i+5] = intramatrix0   [i+6] * j;
  486.                 nonintramatrices[j][i+7] = nonintramatrix0[i+7] * j;
  487.                 intramatrices   [j][i+7] = intramatrix0   [i+7] * j;
  488.             }
  489.         }
  490.         
  491.         mpeg_ready_state = MPEG_READY_MMX;
  492.  
  493.         
  494.     } else if (!MMX_enabled && mpeg_ready_state != MPEG_READY_SCALAR) {
  495.         int i,j;
  496.  
  497.         for(j=0; j<32; j++) {
  498.             for(i=0;i<64;i++) {
  499.                 nonintramatrices[j][i] = nonintramatrix0[i]*j;
  500.                 intramatrices[j][i] = intramatrix0[i]*j;
  501.             }
  502.  
  503.             IDCT_norm(intramatrices[j]);
  504.             IDCT_norm(nonintramatrices[j]);
  505.         }
  506.  
  507.         mpeg_ready_state = MPEG_READY_SCALAR;
  508.     }
  509.  
  510. #ifdef STATISTICS
  511.     memset(&stats, 0, sizeof stats);
  512. #endif
  513.  
  514. #ifdef TIME_TRIALS
  515.     __int64 time_start, time_end;
  516.  
  517.     __asm {
  518.         rdtsc
  519.         mov dword ptr time_start+0,eax
  520.         mov dword ptr time_start+4,edx
  521.     };
  522.  
  523. #endif
  524.  
  525.  
  526.  
  527.     frame_type = -1;
  528.  
  529.     ptr[len-4] = 0;
  530.     ptr[len-3] = 0;
  531.     ptr[len-2] = 1;
  532.     ptr[len-1] = (char)0xff;
  533.  
  534.     while(ptr < limit) {
  535.         do {
  536.             if (ptr>limit) goto advance;
  537.             while(*ptr++) if (ptr>limit) goto advance;
  538.         } while(ptr[0] != 0 || ptr[1] != 1);
  539.  
  540.         type = ptr[2];
  541.         ptr += 3;
  542.  
  543. //        _RPT1(0,"Packet type %02x\n", type);
  544.  
  545.         switch(type) {
  546.         case VIDPKT_TYPE_PICTURE_START:
  547.             video_process_picture_start_packet(ptr);
  548.             break;
  549.         default:
  550.             if (type >= VIDPKT_TYPE_SLICE_START_MIN && type <= VIDPKT_TYPE_SLICE_START_MAX)
  551.                 video_process_picture_slice(ptr, type);
  552.         }
  553.     }
  554.  
  555.     if (MMX_enabled)
  556.         __asm emms
  557.  
  558. #ifdef TIME_TRIALS
  559.     __asm {
  560.         rdtsc
  561.         mov dword ptr time_end+0,eax
  562.         mov dword ptr time_end+4,edx
  563.     };
  564.  
  565.     ++timetrials.counts[frame_type-1];
  566.     timetrials.cycles[frame_type-1] += (time_end - time_start);
  567.     timetrials.totalcycles += (time_end - time_start);
  568.  
  569.     if (!(++timetrials.totalframes & 63)) {
  570.         static char buf[256];
  571.  
  572.         wsprintf(buf, "%d I-frames (%d, %d%%), %d P-frames (%d, %d%%), %d B-frames (%d, %d%%)\n"
  573.             ,timetrials.counts[0]
  574.             ,timetrials.counts[0] ? (int)(timetrials.cycles[0] / timetrials.counts[0]) : 0
  575.             ,timetrials.counts[0] ? (int)((timetrials.cycles[0]*100)/timetrials.totalcycles) : 0
  576.             ,timetrials.counts[1]
  577.             ,timetrials.counts[1] ? (int)(timetrials.cycles[1] / timetrials.counts[1]) : 0
  578.             ,timetrials.counts[1] ? (int)((timetrials.cycles[1]*100)/timetrials.totalcycles) : 0
  579.             ,timetrials.counts[2]
  580.             ,timetrials.counts[2] ? (int)(timetrials.cycles[2] / timetrials.counts[2]) : 0
  581.             ,timetrials.counts[2] ? (int)((timetrials.cycles[2]*100)/timetrials.totalcycles) : 0);
  582.         OutputDebugString(buf);
  583.     }
  584.  
  585. #endif
  586.  
  587.  
  588. advance:
  589.  
  590. #ifdef DISPLAY_INTER_COUNT
  591.     memset(U_dest, 0x80, uv_pitch * mbHeight * 8);
  592.     memset(V_dest, 0x80, uv_pitch * mbHeight * 8);
  593. #endif
  594.  
  595.     switch(frame_type) {
  596.     case I_FRAME:
  597.         mpeg_swap_buffers(MPEG_BUFFER_FORWARD, MPEG_BUFFER_BACKWARD);
  598.  
  599.         buffers[MPEG_BUFFER_FORWARD].frame_num = frame_num;
  600.  
  601.         reset_flag = FALSE;
  602.  
  603.         break;
  604.     case P_FRAME:
  605.         mpeg_swap_buffers(MPEG_BUFFER_FORWARD, MPEG_BUFFER_BACKWARD);
  606.  
  607.         buffers[MPEG_BUFFER_FORWARD].frame_num = frame_num;
  608.         reset_flag = FALSE;
  609.         break;
  610.  
  611.     case B_FRAME:
  612.         buffers[MPEG_BUFFER_BIDIRECTIONAL].frame_num = frame_num;
  613.         break;
  614.  
  615. #ifdef _DEBUG
  616.     default:
  617.         throw MyError("Invalid frame type");
  618. #endif
  619.     };
  620.  
  621.  
  622. #ifdef STATISTICS
  623.     _RPT2(0,"--- Frame #%d statistics (%c-frame)\n", frame_num, " IPBD567"[frame_type]);
  624.     _RPT2(0,"\tCoded block pattern: %7d/%d macroblocks\n", stats.coded_block_pattern, mbWidth*mbHeight);
  625.     _RPT0(0,"\n");
  626. #endif
  627. }
  628.  
  629. void mpeg_swap_buffers(int buffer1, int buffer2) {
  630.     MPEGBuffer b;
  631.  
  632.     b = buffers[buffer1];
  633.     buffers[buffer1] = buffers[buffer2];
  634.     buffers[buffer2] = b;
  635. }
  636.  
  637. int mpeg_lookup_frame(int frame) {
  638. //    _RPT4(0,"Looking for %ld (%ld/%ld/%ld)\n", frame, buffers[0].frame_num, buffers[1].frame_num, buffers[2].frame_num);
  639.  
  640.     for(int i=0; i<(sizeof buffers/sizeof buffers[0]); i++)
  641.         if (buffers[i].frame_num == frame)
  642.             return i;
  643.  
  644.     return -1;
  645. }
  646.  
  647. ////////////////////////////////////////////////////////////////////////////////////////
  648.  
  649. static int *intramatrix;
  650. static int *nonintramatrix;
  651.  
  652. static int forw_vector_full_pel, forw_vector_bits;
  653. static int back_vector_full_pel, back_vector_bits;
  654.  
  655. static int forw_vector_mask, back_vector_mask;
  656. static int forw_vector_extend, back_vector_extend;
  657.  
  658. static int forw_vector_x, forw_vector_y;
  659. static int back_vector_x, back_vector_y;
  660.  
  661. /////////////////////////////
  662.  
  663. static void mpeg_set_destination_buffer(int id) {
  664.     Y_dest = buffers[id].Y;
  665.     U_dest = buffers[id].U;
  666.     V_dest = buffers[id].V;
  667. }
  668.  
  669. static void video_process_picture_start_packet(char *ptr) {
  670.     CMemoryBitInput bits(ptr);
  671.     long temp_rf = bits.get(10);
  672.  
  673.     frame_type = bits.get(3);
  674.  
  675. //    _RPT2(0,"Processing %c-frame (#%d)\n", " IPBD567"[frame_type], temp_rf);
  676.  
  677.     switch(frame_type) {
  678.     case I_FRAME:        // I-frames have no prediction
  679.         mpeg_set_destination_buffer(MPEG_BUFFER_BACKWARD);
  680. //        _RPT1(0,"Processing I-frame (#%d)\n", temp_rf);
  681.         break;
  682.  
  683.     case P_FRAME:        // P-frames predict back to the last I or P
  684.         mpeg_set_destination_buffer(MPEG_BUFFER_BACKWARD);
  685. //        _RPT2(0,"Processing P-frame (#%d) (forward: %ld)\n", temp_rf, buffers[MPEG_BUFFER_FORWARD].frame_num);
  686.  
  687.         Y_forw = buffers[MPEG_BUFFER_FORWARD].Y;
  688.         U_forw = buffers[MPEG_BUFFER_FORWARD].U;
  689.         V_forw = buffers[MPEG_BUFFER_FORWARD].V;
  690.         break;
  691.  
  692.     case B_FRAME:        // B-frames predict back to the last I or P and forward to the next P
  693.         mpeg_set_destination_buffer(MPEG_BUFFER_BIDIRECTIONAL);
  694. //        _RPT3(0,"Processing B-frame (#%d) (f: %ld  b: %ld)\n", temp_rf, buffers[MPEG_BUFFER_BACKWARD].frame_num, buffers[MPEG_BUFFER_FORWARD].frame_num);
  695.         Y_back = buffers[MPEG_BUFFER_FORWARD].Y;
  696.         U_back = buffers[MPEG_BUFFER_FORWARD].U;
  697.         V_back = buffers[MPEG_BUFFER_FORWARD].V;
  698.         if (reset_flag) {
  699.             Y_forw = Y_back;
  700.             U_forw = U_back;
  701.             V_forw = V_back;
  702.         } else {
  703.             Y_forw = buffers[MPEG_BUFFER_BACKWARD].Y;
  704.             U_forw = buffers[MPEG_BUFFER_BACKWARD].U;
  705.             V_forw = buffers[MPEG_BUFFER_BACKWARD].V;
  706.         }
  707.         break;
  708.  
  709.     case D_FRAME:
  710.         throw MyError("D-type frames not supported");
  711.  
  712.     default:
  713.         throw MyError("Unknown frame type 0x%d", frame_type);
  714.     }
  715.  
  716.  
  717.     bits.get(16);    // VBV_delay
  718.     if (frame_type == P_FRAME || frame_type == B_FRAME) {
  719.         forw_vector_full_pel    = bits.get();
  720.         forw_vector_bits        = bits.get(3)-1;
  721.         forw_vector_mask        = (32<<forw_vector_bits)-1;
  722.         forw_vector_extend        = ~((16<<forw_vector_bits)-1);
  723.     }
  724.  
  725.     if (frame_type == B_FRAME) {
  726.         back_vector_full_pel    = bits.get();
  727.         back_vector_bits        = bits.get(3)-1;
  728.         back_vector_mask        = (32<<back_vector_bits)-1;
  729.         back_vector_extend        = ~((16<<back_vector_bits)-1);
  730.     }
  731. }
  732.  
  733. ////////////////////////////////////////////////////
  734.  
  735. static int dct_dc_y_past, dct_dc_u_past, dct_dc_v_past;
  736.  
  737. extern int dct_coeff[64];
  738.  
  739. #define MBF_NEW_QUANT        (16)
  740. #define MBF_FORWARD            (8)
  741. #define MBF_BACKWARD        (4)
  742. #define MBF_PATTERN            (2)
  743. #define MBF_INTRA            (1)
  744.  
  745. static CMemoryBitInput bits;
  746. static int macro_block_flags;
  747.  
  748. YUVPixel *dstY, *dstU, *dstV;
  749.  
  750. //////////////////////
  751.  
  752.  
  753. extern "C" void IDCT_mmx(signed short *dct_coeff, void *dst, long pitch, int intra_flag, int pos);
  754. extern "C" void IDCT_isse(signed short *dct_coeff, void *dst, long pitch, int intra_flag, int pos);
  755.  
  756.  
  757. static void decode_mblock(YUVPixel *dst, long modulo, long DC_val) {
  758. #ifdef MB_STATS
  759.  
  760. #ifdef MB_SPLIT_STATS
  761. #define MB_DECLARE_STAT(x)        static int x##_intra=0, x##_inter=0;
  762. #define MB_STAT_INC(x)            (macro_block_flags & MBF_INTRA ? (++x##_intra) : (++x##_inter))
  763. #else
  764. #define MB_DECLARE_STAT(x)        static int x=0;
  765. #define MB_STAT_INC(x)            (++x)
  766. #endif
  767.  
  768. MB_DECLARE_STAT(st_level1_idx0);
  769. MB_DECLARE_STAT(st_level1_idx1);
  770. MB_DECLARE_STAT(st_exit);
  771. MB_DECLARE_STAT(st_short);
  772. MB_DECLARE_STAT(st_long);
  773. MB_DECLARE_STAT(st_vshort);
  774. MB_DECLARE_STAT(st_escape);
  775. MB_DECLARE_STAT(st_first_short);
  776. MB_DECLARE_STAT(st_first_long);
  777.  
  778. #else
  779. #define MB_STAT_INC(x)
  780. #endif
  781.  
  782.     const int *idx=zigzag;
  783.     int level;
  784.     int pos=0;
  785.     int coeff_count = 0;
  786.     const int *quant_matrix = intramatrix;
  787.     long v;
  788.     int sign = 0;
  789.  
  790.     dct_coeff[0] = DC_val;
  791.  
  792.     v = bits.peek(12);
  793.     if (!(macro_block_flags & MBF_INTRA)) {
  794.         quant_matrix = nonintramatrix;
  795.         sign = 1;
  796.  
  797.         if (v < 0x800) {
  798.             idx = zigzag-1;
  799.             dct_coeff[0]=0;
  800.  
  801.             MB_STAT_INC(st_first_long);
  802.         } else {
  803.  
  804.             if (v & 0x400)
  805.                 dct_coeff[0] = (-3*quant_matrix[0] + 128) >> 8;
  806.             else
  807.                 dct_coeff[0] = (3*quant_matrix[0] + 128) >> 8;
  808.  
  809.             bits.skip(2);
  810.             v = bits.peek(12);
  811.  
  812.             MB_STAT_INC(st_first_short);
  813.         }
  814.     }
  815.  
  816.     // macroblock statistics from nuku.mpg:
  817.     //
  818.     //    2883584 mblocks
  819.     //        7142656 (42%)        very short
  820.     //        3457222 (20%)        level 1, idx_run = 0
  821.     //        1604394 ( 9%)        level 1, idx_run = 1
  822.     //         937613 ( 5%)        long
  823.     //         451518 ( 2%)        short
  824.     //         161300 ( 0%)        escape
  825.     //        1457101 (50%)        first long
  826.     //         705505 (24%)        first short
  827.  
  828.     // nuku1.mpg:
  829.     //    47710208 mblocks
  830.     //        120471300 (43%)        very short
  831.     //         52059388 (18%)        level 1, idx_run = 0
  832.     //         47710208 (17%)        exits
  833.     //         27499741 ( 9%)        level 1, idx_run = 1
  834.     //         18368812 ( 6%)        long
  835.     //          7911139 ( 2%)        short
  836.     //          4948686 ( 1%)        escape
  837.     //         29281756 (61%)        first long
  838.     //         14165596 (29%)        first short
  839.  
  840.     for(;;v = bits.peek(12)) {
  841.         int level_sign = 0;
  842.  
  843.         if (v >= 0x080) {                // 080-FFF        (90%)
  844.             if (v < 0x600) {            // 080-5FF very short (40%)
  845.                 int t = (v>>4);
  846.                 int bcnt;
  847.  
  848.                 bcnt = mpeg_dct_coeff_decode0[t*4+2-32];
  849.                 idx += mpeg_dct_coeff_decode0[t*4+0-32];
  850.                 level = mpeg_dct_coeff_decode0[t*4+1-32];
  851.  
  852.                 _ASSERT(level != 0);
  853.  
  854.                 bits.skip(bcnt);
  855.  
  856.                 if (v & mpeg_dct_coeff_decode0[t*4+3-32])
  857.                     level_sign = -1;
  858.  
  859.                 MB_STAT_INC(st_vshort);
  860.  
  861.             } else if (v >= 0x0c00) {    // C00-FFF level1-idx0 (20%)
  862.                 bits.skip(3);
  863.  
  864.                 ++idx;
  865.                 level = 1;
  866.  
  867.                 if (v & 0x200)
  868.                     level_sign = -1;
  869.  
  870.                 MB_STAT_INC(st_level1_idx0);
  871.  
  872.             } else if (v >= 0x800) {    // 800-BFF
  873.                 bits.skip(2);
  874.  
  875.                 MB_STAT_INC(st_exit);
  876.  
  877.                 break;
  878.             } else {                    // 600-7FF
  879.                 bits.skip(4);
  880.                 idx += 2;
  881.  
  882.                 level = 1;
  883.                 if (v & 0x100)
  884.                     level_sign = -1;
  885.  
  886.                 MB_STAT_INC(st_level1_idx1);
  887.  
  888.             }
  889.         } else {
  890.             if (v >= 0x040) {
  891.                 bits.skip(6);
  892.                 idx += bits.get(6)+1;
  893.                 level = bits.get_signed(8);
  894.  
  895. //                _ASSERT(level != 0);
  896.  
  897.                 if (!(level & 0x7f)) {
  898.                     level <<= 1;
  899.                     level |= bits.get(8);
  900.                 }
  901.  
  902.                 if (level<0) {
  903.                     level = -level;
  904.                     level_sign = -1;
  905.                 }
  906.  
  907.                 MB_STAT_INC(st_escape);
  908.  
  909.             } else if (v >= 0x020) {
  910.                 int t = (v>>2);
  911.  
  912.                 idx += mpeg_dct_coeff_decode1[t*2+0-16]+1;
  913.                 level = mpeg_dct_coeff_decode1[t*2+1-16];
  914.  
  915.                 _ASSERT(level != 0);
  916.  
  917.                 MB_STAT_INC(st_short);
  918.  
  919.                 bits.skip(11);
  920.                 if (v & 2)
  921.                     level_sign = -1;
  922.             } else {
  923.                 int t, bcnt;
  924.  
  925.                 MB_STAT_INC(st_long);
  926.  
  927.                 bits.skip(7);
  928.                 v = bits.peek(10);
  929.                 t = v>>1;
  930.                 bcnt = mpeg_dct_coeff_decode2[t*4+2];
  931.                 idx += mpeg_dct_coeff_decode2[t*4+0]+1;
  932.                 level = mpeg_dct_coeff_decode2[t*4+1];
  933.                 bits.skip(bcnt);
  934.  
  935.                 _ASSERT(level != 0);
  936.  
  937.                 if (v & (0x400>>bcnt))
  938.                     level_sign = -1;
  939.             }
  940.         }
  941.  
  942.         ++coeff_count;
  943.  
  944. #ifdef DCT_POSITION_CHECKING
  945.         if (idx >= zigzag+64) {
  946.             pos = 63;
  947.             break;
  948.         }
  949. #endif
  950.  
  951.         pos = *idx;
  952.  
  953.         // quant_matrix: 0...255
  954.         // level: -256...255
  955.  
  956.         _ASSERT(level != 0);
  957.  
  958.         // We need to oddify coefficients down toward zero.
  959.         // can't - already added DCT>FFT matrix!
  960.  
  961.         level = (((level*2+sign) * quant_matrix[pos] + 128) >> 8);
  962.  
  963.         // Negate coefficient if necessary.
  964.  
  965.         dct_coeff[pos] = (level ^ level_sign) - level_sign;
  966.  
  967.     }
  968.  
  969. #ifdef MB_STATS
  970. #ifdef MB_SPLIT_STATS
  971.     if (st_exit_intra && !(st_exit_intra & 262143)) {
  972.         static char buf[256];
  973.         int total    = st_exit_intra
  974.                     + st_short_intra
  975.                     + st_long_intra
  976.                     + st_level1_idx0_intra
  977.                     + st_level1_idx1_intra
  978.                     + st_vshort_intra
  979.                     + st_escape_intra;
  980.  
  981.         sprintf(buf, "[intra] %ld mblocks, %ld vshort (%d%%), %ld sh (%d%%), %ld ln (%d%%), %ld 1-0 (%d%%), %ld 1-1 (%d%%), %ld E (%d%%), %ld f-s (%d%%), %ld f-l (%d%%)\n"
  982.                     ,st_exit_intra
  983.                     ,st_vshort_intra        ,(int)((st_vshort_intra            *100i64)/total)
  984.                     ,st_short_intra            ,(int)((st_short_intra            *100i64)/total)
  985.                     ,st_long_intra            ,(int)((st_long_intra            *100i64)/total)
  986.                     ,st_level1_idx0_intra    ,(int)((st_level1_idx0_intra    *100i64)/total)
  987.                     ,st_level1_idx1_intra    ,(int)((st_level1_idx1_intra    *100i64)/total)
  988.                     ,st_escape_intra        ,(int)((st_escape_intra            *100i64)/total)
  989.                     ,st_first_short_intra    ,(int)((st_first_short_intra    *100i64)/total)
  990.                     ,st_first_long_intra    ,(int)((st_first_long_intra        *100i64)/total)
  991.                     );
  992.         OutputDebugString(buf);
  993.     }
  994.     if (st_exit_inter && !(st_exit_inter & 262143)) {
  995.         static char buf[256];
  996.         int total    = st_exit_inter
  997.                     + st_short_inter
  998.                     + st_long_inter
  999.                     + st_level1_idx0_inter
  1000.                     + st_level1_idx1_inter
  1001.                     + st_vshort_inter
  1002.                     + st_escape_inter;
  1003.  
  1004.         sprintf(buf, "[inter] %ld mblocks, %ld vshort (%d%%), %ld sh (%d%%), %ld ln (%d%%), %ld 1-0 (%d%%), %ld 1-1 (%d%%), %ld E (%d%%), %ld f-s (%d%%), %ld f-l (%d%%)\n"
  1005.                     ,st_exit_inter
  1006.                     ,st_vshort_inter        ,(int)((st_vshort_inter            *100i64)/total)
  1007.                     ,st_short_inter            ,(int)((st_short_inter            *100i64)/total)
  1008.                     ,st_long_inter            ,(int)((st_long_inter            *100i64)/total)
  1009.                     ,st_level1_idx0_inter    ,(int)((st_level1_idx0_inter    *100i64)/total)
  1010.                     ,st_level1_idx1_inter    ,(int)((st_level1_idx1_inter    *100i64)/total)
  1011.                     ,st_escape_inter        ,(int)((st_escape_inter            *100i64)/total)
  1012.                     ,st_first_short_inter    ,(int)((st_first_short_inter    *100i64)/total)
  1013.                     ,st_first_long_inter    ,(int)((st_first_long_inter        *100i64)/total)
  1014.                     );
  1015.         OutputDebugString(buf);
  1016.     }
  1017. #else
  1018.     if (!(st_exit & 262143)) {
  1019.         static char buf[256];
  1020.         int total = st_exit + st_short + st_long + st_level1_idx0 + st_level1_idx1 + st_vshort + st_escape;
  1021.  
  1022.         sprintf(buf, "%ld mblocks, %ld vshort (%d%%), %ld sh (%d%%), %ld ln (%d%%), %ld 1-0 (%d%%), %ld 1-1 (%d%%), %ld E (%d%%), %ld f-s (%d%%), %ld f-l (%d%%)\n"
  1023.                     ,st_exit
  1024.                     ,st_vshort,(int)((st_vshort*100i64)/total)
  1025.                     ,st_short,(int)((st_short*100i64)/total)
  1026.                     ,st_long,(int)((st_long*100i64)/total)
  1027.                     ,st_level1_idx0,(int)((st_level1_idx0*100i64)/total)
  1028.                     ,st_level1_idx1,(int)((st_level1_idx1*100i64)/total)
  1029.                     ,st_escape,(int)((st_escape*100i64)/total)
  1030.                     ,st_first_short, (int)((st_first_short*100i64)/total)
  1031.                     ,st_first_long, (int)((st_first_long*100i64)/total)
  1032.                     );
  1033.         OutputDebugString(buf);
  1034.     }
  1035. #endif
  1036. #endif
  1037.  
  1038.     dct_coeff[0] += ROUNDVAL;
  1039.  
  1040.     if (!pos || coeff_count<=1) {
  1041.         if (macro_block_flags & MBF_INTRA)
  1042.             IDCT_fast_put(pos, dst, modulo);
  1043.         else
  1044.             IDCT_fast_add(pos, dst, modulo);
  1045.     } else {
  1046.         IDCT(dst, modulo, macro_block_flags & MBF_INTRA);
  1047.     }
  1048. }
  1049.  
  1050. static void decode_mblock_MMX(YUVPixel *dst, long modulo, long DC_val) {
  1051.  
  1052.     const int *idx=zigzag_MMX;
  1053.     int level;
  1054.     int pos=0;
  1055.     const int *quant_matrix = intramatrix;
  1056.     unsigned long v;
  1057.     int sign = 0;
  1058.     signed short coeff0[67];
  1059.     signed short *const coeff = (signed short *)(((long)coeff0 + 7) & 0xfffffff8);
  1060.  
  1061.     memset(coeff, 0, 64*sizeof(signed short));
  1062.  
  1063.     coeff[0] = (DC_val + 128) >> 8;
  1064.  
  1065.     if (!(macro_block_flags & MBF_INTRA)) {
  1066.         quant_matrix = nonintramatrix;
  1067.         sign = 1;
  1068.  
  1069.         v = bits.peek();
  1070.  
  1071.         if (v < 0x80000000) {
  1072.             idx = zigzag_MMX-1;
  1073.             coeff[0]=0;
  1074.  
  1075.             MB_STAT_INC(st_first_long);
  1076.         } else {
  1077.  
  1078.             coeff[0] = (((3*quant_matrix[0] + 8) >> 4) - 1) | 1;
  1079.  
  1080.             if (v & 0x40000000)
  1081.                 coeff[0] = -coeff[0];
  1082.  
  1083.             bits.skip(2);
  1084.  
  1085.             MB_STAT_INC(st_first_short);
  1086.         }
  1087.     }
  1088.     
  1089.     // macroblock statistics from nuku.mpg:
  1090.     //
  1091.     //    2883584 mblocks
  1092.     //        7142656 (42%)        very short
  1093.     //        3457222 (20%)        level 1, idx_run = 0
  1094.     //        1604394 ( 9%)        level 1, idx_run = 1
  1095.     //         937613 ( 5%)        long
  1096.     //         451518 ( 2%)        short
  1097.     //         161300 ( 0%)        escape
  1098.     //        1457101 (50%)        first long
  1099.     //         705505 (24%)        first short
  1100.  
  1101.     // nuku1.mpg:
  1102.     //    47710208 mblocks
  1103.     //        120471300 (43%)        very short
  1104.     //         52059388 (18%)        level 1, idx_run = 0
  1105.     //         47710208 (17%)        exits
  1106.     //         27499741 ( 9%)        level 1, idx_run = 1
  1107.     //         18368812 ( 6%)        long
  1108.     //          7911139 ( 2%)        short
  1109.     //          4948686 ( 1%)        escape
  1110.     //         29281756 (61%)        first long
  1111.     //         14165596 (29%)        first short
  1112.  
  1113.     for(;;) {
  1114.         int level_sign = 0;
  1115.  
  1116.         v = bits.peek();
  1117.  
  1118.         if (PREDICT(080, v >= 0x08000000)) {                // 080-FFF        (90%)
  1119.             if (PREDICT(600, v < 0x60000000)) {            // 080-5FF very short (40%)
  1120.                 int t = (v>>24);
  1121.                 int bcnt;
  1122.  
  1123.                 bcnt = mpeg_dct_coeff_decode0[t*4+2-32];
  1124.                 idx += mpeg_dct_coeff_decode0[t*4+0-32];
  1125.                 level = mpeg_dct_coeff_decode0[t*4+1-32];
  1126.  
  1127.                 _ASSERT(level != 0);
  1128.  
  1129.                 bits.skip8(bcnt);
  1130.  
  1131. //                if (v & mpeg_dct_coeff_decode0[t*4+3-32])
  1132. //                    level_sign = -1;
  1133.                 level_sign = (((signed long)(v>>20) & mpeg_dct_coeff_decode0[t*4+3-32])+0x7FFFFFFF) >> 31;
  1134.  
  1135.                 MB_STAT_INC(st_vshort);
  1136.  
  1137.             } else if (PREDICT(C00, v >= 0xc0000000)) {    // C00-FFF level1-idx0 (20%)
  1138.                 bits.skipconst(3);
  1139.  
  1140.                 ++idx;
  1141.  
  1142.                 level = 1;
  1143.  
  1144. //                if (v & 0x200)
  1145. //                    level_sign = -1;
  1146.  
  1147.                 level_sign = (((signed long)v&0x20000000)+0x7FFFFFFF) >> 31;
  1148.  
  1149.                 MB_STAT_INC(st_level1_idx0);
  1150.  
  1151.             } else if (PREDICT(800, v >= 0x80000000)) {    // 800-BFF
  1152.                 bits.skipconst(2);
  1153.  
  1154.                 MB_STAT_INC(st_exit);
  1155.  
  1156.                 break;
  1157.             } else {                    // 600-7FF
  1158.                 bits.skipconst(4);
  1159.                 idx += 2;
  1160.  
  1161.                 level = 1;
  1162. //                if (v & 0x100)
  1163. //                    level_sign = -1;
  1164.  
  1165.                 level_sign = (((signed long)v&0x10000000)+0x7FFFFFFF) >> 31;
  1166.  
  1167.                 MB_STAT_INC(st_level1_idx1);
  1168.  
  1169.             }
  1170.         } else {
  1171.             if (PREDICT(040, v >= 0x04000000)) {
  1172.                 bits.skipconst(6);
  1173.                 idx += bits.getconst(6)+1;
  1174.                 level = bits.get_signed_const(8);
  1175.  
  1176. //                _ASSERT(level != 0);
  1177.  
  1178.                 if (!(level & 0x7f)) {
  1179.                     level <<= 1;
  1180.                     level |= bits.getconst(8);
  1181.                 }
  1182.  
  1183.                 if (level<0) {
  1184.                     level = -level;
  1185.                     level_sign = -1;
  1186.                 }
  1187.  
  1188.                 MB_STAT_INC(st_escape);
  1189.  
  1190.             } else if (PREDICT(020, v >= 0x02000000)) {
  1191.                 int t = (v>>22);
  1192.  
  1193.                 idx += mpeg_dct_coeff_decode1[t*2+0-16]+1;
  1194.                 level = mpeg_dct_coeff_decode1[t*2+1-16];
  1195.  
  1196.                 _ASSERT(level != 0);
  1197.  
  1198.                 MB_STAT_INC(st_short);
  1199.  
  1200.                 bits.skipconst(11);
  1201. //                if (v & 2)
  1202. //                    level_sign = -1;
  1203.                 level_sign = -((signed long)v&0x00200000)>>31;
  1204.             } else {
  1205.                 int t, bcnt;
  1206.  
  1207.                 MB_STAT_INC(st_long);
  1208.  
  1209.                 bits.skipconst(7);
  1210.                 v = bits.peek(10);
  1211.                 t = v>>1;
  1212.                 bcnt = mpeg_dct_coeff_decode2[t*4+2];
  1213.                 idx += mpeg_dct_coeff_decode2[t*4+0]+1;
  1214.                 level = mpeg_dct_coeff_decode2[t*4+1];
  1215.                 bits.skip(bcnt);
  1216.  
  1217.                 _ASSERT(level != 0);
  1218.  
  1219. //                if (v & (0x400>>bcnt))
  1220. //                    level_sign = -1;
  1221.                 level_sign = -((signed long)v&(0x400>>bcnt))>>31;
  1222.             }
  1223.         }
  1224.  
  1225. #ifdef DCT_POSITION_CHECKING
  1226.         if (idx >= zigzag_MMX+64) {
  1227.             pos = 63;
  1228.             break;
  1229.         }
  1230. #endif
  1231.  
  1232.         pos = *idx;
  1233.  
  1234.         // quant_matrix: 0...255
  1235.         // level: -256...255
  1236.  
  1237.         _ASSERT(level != 0);
  1238.  
  1239.         // We need to oddify coefficients down toward zero.
  1240.  
  1241.         level = ((((level*2+sign) * quant_matrix[pos] + 8) >> 4) - 1) | 1;
  1242.  
  1243.         // Negate coefficient if necessary.
  1244.  
  1245.         coeff[pos] = (level ^ level_sign) - level_sign;
  1246.  
  1247.     }
  1248.  
  1249. //    ++lpos_stats[pos];
  1250.  
  1251. #ifdef DISPLAY_INTER_COUNT
  1252.     if (macro_block_flags & MBF_INTRA) {
  1253.         dct_coeff[0] = (32<<8)+ROUNDVAL;
  1254.         IDCT_fast_put(pos, dst, modulo);
  1255.     } else {
  1256.         dct_coeff[0] = (128<<8)+ROUNDVAL;
  1257.         IDCT_fast_add(pos, dst, modulo);
  1258.     }
  1259. #else
  1260.     if (!pos) {
  1261.         dct_coeff[0] = (coeff[0]<<8)+ROUNDVAL;
  1262.  
  1263.         if (macro_block_flags & MBF_INTRA)
  1264.             IDCT_fast_put(pos, dst, modulo);
  1265.         else
  1266.             IDCT_fast_add(pos, dst, modulo);
  1267.     } else
  1268.         (ISSE_enabled ? IDCT_isse : IDCT_mmx)(coeff, dst, modulo, !!(macro_block_flags & MBF_INTRA), pos);
  1269. #endif
  1270. }
  1271.  
  1272. static void decode_mblock_Y(YUVPixel *dst) {
  1273. //    memset(dct_coeff, 0, sizeof dct_coeff);
  1274. #ifdef DEBUG
  1275.     for(int i=0; i<dct_coeff; i++)
  1276.         _ASSERT(dct_coeff[i] == 0);
  1277. #endif
  1278.  
  1279.     if ((macro_block_flags & MBF_INTRA)) {
  1280.         int size, value = 0;
  1281.  
  1282.         {
  1283.             long v=bits.peek(7)*2;
  1284.  
  1285.             if (v < 64*2) {
  1286.                 bits.skip8(2);
  1287.                 size = (v>>6)+1;
  1288.             } else {
  1289.                 size = mpeg_dct_size_luminance_decode[v - 64*2];
  1290.                 bits.skip(mpeg_dct_size_luminance_decode[v+1 - 64*2]);
  1291.             }
  1292.         }
  1293.  
  1294.         if (size) {
  1295.             int halfval;
  1296.  
  1297.             value = bits.get(size);
  1298.             halfval = 1 << (size-1);
  1299.  
  1300.             if (value < halfval)
  1301.                 value = (value+1) - 2*halfval;
  1302.  
  1303.             value <<= 11;
  1304.         }
  1305.  
  1306.         (MMX_enabled ? decode_mblock_MMX : decode_mblock)(dst, y_pitch, dct_dc_y_past += value);
  1307.     } else
  1308.         (MMX_enabled ? decode_mblock_MMX : decode_mblock)(dst, y_pitch, 0);
  1309. }
  1310.  
  1311. static void decode_mblock_UV(YUVPixel *dst, int& dc_ref) {
  1312. //    memset(dct_coeff, 0, sizeof dct_coeff);
  1313. #ifdef DEBUG
  1314.     for(int i=0; i<dct_coeff; i++)
  1315.         _ASSERT(dct_coeff[i] == 0);
  1316. #endif
  1317.  
  1318.     if ((macro_block_flags & MBF_INTRA)) {
  1319.         int size, value=0;
  1320.  
  1321.         {
  1322.             long v=bits.peek(8)*2;
  1323.  
  1324.             if (v < 192*2) {
  1325.                 size = v>>7;
  1326.                 bits.skip8(2);
  1327.             } else {
  1328.                 size = mpeg_dct_size_chrominance_decode[v - 192*2];
  1329.                 bits.skip(mpeg_dct_size_chrominance_decode[v+1 - 192*2]);
  1330.             }
  1331.         }
  1332.  
  1333.         if (size) {
  1334.             int halfval;
  1335.  
  1336.             value = bits.get(size);
  1337.  
  1338.             halfval = 1 << (size-1);
  1339.  
  1340.             if (value < halfval)
  1341.                 value = (value+1) - 2*halfval;
  1342.  
  1343.             value <<= 11;
  1344.  
  1345.         }
  1346.  
  1347.         (MMX_enabled ? decode_mblock_MMX : decode_mblock)(dst, uv_pitch, dc_ref += value);
  1348.  
  1349.     } else
  1350.         (MMX_enabled ? decode_mblock_MMX : decode_mblock)(dst, uv_pitch, 0);
  1351. }
  1352.  
  1353. ///////////////////////////
  1354.  
  1355. static void video_process_picture_slice_I(char *ptr, int type) {
  1356.     long pos_x, pos_y;
  1357.  
  1358.     pos_y = type-1;
  1359.     pos_x = -1;
  1360.  
  1361.     dstY = Y_dest + 16 *  y_pitch * pos_y - 16;
  1362.     dstU = U_dest +  8 * uv_pitch * pos_y - 8;
  1363.     dstV = V_dest +  8 * uv_pitch * pos_y - 8;
  1364.  
  1365.     do {
  1366.         int inc = 0;
  1367.         int i;
  1368.  
  1369.         // 00000001111 (00F) -> padding
  1370.         // 00000001000 (008) -> skip 33 more
  1371.         // 1 -> skip 1
  1372.  
  1373.         i = bits.peek(11);
  1374.         while(i == 0xf) {
  1375.             bits.skip(11);
  1376.             i = bits.peek(11);
  1377.         }
  1378.         while(i == 0x8) {
  1379.             bits.skip(11);
  1380.             i = bits.peek(11);
  1381.             inc += 33;
  1382.             dct_dc_y_past = dct_dc_u_past = dct_dc_v_past = MIDVAL;
  1383.         }
  1384.         
  1385.         if (i&0x400) {
  1386.             bits.skip();
  1387.             ++inc;
  1388.         } else if (i>=96) {
  1389.             i>>=4;
  1390.             bits.skip(mpeg_macro_block_inc_decode2[i*2+1-12]);
  1391.             inc += mpeg_macro_block_inc_decode2[i*2+0-12];
  1392.         } else {
  1393.             bits.skip(mpeg_macro_block_inc_decode[i*2+1]);
  1394.             inc += mpeg_macro_block_inc_decode[i*2+0];
  1395.         }
  1396.  
  1397.         pos_x += inc;
  1398.  
  1399.         while(pos_x >= mbWidth) {
  1400.             pos_x-=mbWidth;
  1401.             pos_y++;
  1402.             if (pos_y >= mbHeight)
  1403.                 return;
  1404.             dstY += y_modulo;
  1405.             dstU += uv_modulo;
  1406.             dstV += uv_modulo;
  1407.         }
  1408.  
  1409.         dstY += 16*inc;
  1410.         dstU += 8*inc;
  1411.         dstV += 8*inc;
  1412.  
  1413.         _ASSERT(dstY >= Y_dest);
  1414.         _ASSERT(dstY <= Y_dest + y_pitch * 16 * (mbHeight-1) + 16*(mbWidth-1));
  1415.  
  1416.         macro_block_flags = MBF_INTRA;
  1417.  
  1418.         if (!bits.get_flag()) {
  1419. //            macro_block_flags |= MBF_NEW_QUANT;
  1420.             bits.skip();
  1421.  
  1422.             int quant_scale = bits.get8(5);
  1423.             intramatrix = intramatrices[quant_scale];
  1424.             nonintramatrix = nonintramatrices[quant_scale];
  1425.         }
  1426.  
  1427.         decode_mblock_Y(dstY);
  1428.         decode_mblock_Y(dstY + 8);
  1429.         decode_mblock_Y(dstY + y_pitch*8);
  1430.         decode_mblock_Y(dstY + y_pitch*8 + 8);
  1431.         decode_mblock_UV(dstU, dct_dc_u_past);
  1432.         decode_mblock_UV(dstV, dct_dc_v_past);
  1433.  
  1434.     } while(!bits.next(23,0));
  1435. }
  1436.  
  1437. static int __inline mpeg_get_motion_component() {
  1438.     long v;
  1439.  
  1440.     v = bits.peek(11);
  1441.     if (v & 0x400) {
  1442.         bits.skip();
  1443.         return 0;
  1444.     } else if (v >= 96) {
  1445.         v = (v-96)>>4;
  1446.         bits.skip(mpeg_motion_code_decode2[v*2+1]);
  1447.         return mpeg_motion_code_decode2[v*2+0];
  1448.     } else {
  1449.         bits.skip(mpeg_motion_code_decode[v*2+1]);
  1450.         return mpeg_motion_code_decode[v*2+0];
  1451.     }
  1452. }
  1453.  
  1454. static void video_process_picture_slice_P(char *ptr, int type) {
  1455.     BOOL is_first_block = TRUE;
  1456.     long pos_x, pos_y;
  1457.  
  1458.     pos_y = type-1;
  1459.     pos_x = -1;
  1460.  
  1461.     dstY = Y_dest + 16 *  y_pitch * pos_y - 16;
  1462.     dstU = U_dest +  8 * uv_pitch * pos_y - 8;
  1463.     dstV = V_dest +  8 * uv_pitch * pos_y - 8;
  1464.  
  1465.     do {
  1466.         int inc = 0;
  1467.         signed char cbp = 0x3f;
  1468.         int i;
  1469.  
  1470.         // 00000001111 (00F) -> padding
  1471.         // 00000001000 (008) -> skip 33 more
  1472.         // 1 -> skip 1
  1473.  
  1474.         i = bits.peek(11);
  1475.         while(i == 0xf) {
  1476.             bits.skip(11);
  1477.             i = bits.peek(11);
  1478.         }
  1479.         while(i == 0x8) {
  1480.             bits.skip(11);
  1481.             i = bits.peek(11);
  1482.             inc += 33;
  1483.         }
  1484.         
  1485.         if (i&0x400) {
  1486.             bits.skip();
  1487.             ++inc;
  1488.         } else if (i>=96) {
  1489.             i >>= 4;
  1490.             bits.skip(mpeg_macro_block_inc_decode2[i*2+1-12]);
  1491.             inc += mpeg_macro_block_inc_decode2[i*2+0-12];
  1492.         } else {
  1493.             bits.skip(mpeg_macro_block_inc_decode[i*2+1]);
  1494.             inc += mpeg_macro_block_inc_decode[i*2+0];
  1495.         }
  1496.  
  1497. //        _RPT3(0,"(%d,%d): inc %d\n", (pos_x+1), pos_y + (pos_x==mbWidth-1?1:0), inc);
  1498.  
  1499. //        _RPT1(0,"skip: %ld\n", inc);
  1500.         if (inc > 1) {
  1501.             dct_dc_y_past = dct_dc_u_past = dct_dc_v_past = MIDVAL;
  1502.  
  1503.             forw_vector_x = forw_vector_y = 0;
  1504.             if (pos_x >= 0)
  1505.                 for(i=1; i<inc; i++) {
  1506.                     ++pos_x;
  1507.                     dstY += 16;
  1508.                     dstU += 8;
  1509.                     dstV += 8;
  1510.  
  1511.                     if(pos_x >= mbWidth) {
  1512.                         pos_x-=mbWidth;
  1513.                         pos_y++;
  1514.  
  1515.                         if (pos_y >= mbHeight)
  1516.                             return;
  1517.  
  1518.                         dstY += y_modulo;
  1519.                         dstU += uv_modulo;
  1520.                         dstV += uv_modulo;
  1521.                     }
  1522.  
  1523.                     video_copy_forward(pos_x, pos_y);
  1524.                 }
  1525.             else {
  1526.                 pos_x += inc-1;
  1527.                 dstY += 16*(inc-1);
  1528.                 dstU += 8*(inc-1);
  1529.                 dstV += 8*(inc-1);
  1530.             }
  1531. //            } else pos_x += inc-1;
  1532.         }
  1533.  
  1534.         ++pos_x;
  1535.  
  1536.         while (pos_x >= mbWidth) {
  1537.             pos_x-=mbWidth;
  1538.             pos_y++;
  1539.             if (pos_y >= mbHeight)
  1540.                 return;
  1541.             dstY += y_modulo;
  1542.             dstU += uv_modulo;
  1543.             dstV += uv_modulo;
  1544.         }
  1545.  
  1546.         dstY += 16;
  1547.         dstU += 8;
  1548.         dstV += 8;
  1549.  
  1550.         _ASSERT(dstY >= Y_dest);
  1551.         _ASSERT(dstY <= Y_dest + y_pitch * 16 * (mbHeight-1) + 16*(mbWidth-1));
  1552.  
  1553.         {
  1554.             long v=bits.peek(6);
  1555.  
  1556.             if (v>=32) {
  1557.                 macro_block_flags = MBF_FORWARD | MBF_PATTERN;
  1558.                 bits.skip();
  1559.             } else {
  1560.                 macro_block_flags = mpeg_p_type_mb_type_decode[v*2];
  1561.                 bits.skip(mpeg_p_type_mb_type_decode[v*2+1]);
  1562.             }
  1563.         }
  1564.  
  1565.         if (!(macro_block_flags & MBF_INTRA)) {
  1566.             dct_dc_y_past = dct_dc_u_past = dct_dc_v_past = MIDVAL;
  1567.             cbp = 0;
  1568.         }
  1569.  
  1570.         if (macro_block_flags & MBF_NEW_QUANT) {
  1571.             int quant_scale = bits.get8(5);
  1572.             intramatrix = intramatrices[quant_scale];
  1573.             nonintramatrix = nonintramatrices[quant_scale];
  1574.         }
  1575.  
  1576.         if (macro_block_flags & MBF_FORWARD) {                // motion vector for forward prediction exists
  1577.             int motion_x_forw_c, motion_y_forw_c;
  1578.             int motion_x_forw_r, motion_y_forw_r;
  1579.             int delta;
  1580.  
  1581.             motion_x_forw_c = mpeg_get_motion_component();
  1582.  
  1583.             // according to this information the motion vector must be decoded
  1584.  
  1585.             if ((signed char)forw_vector_bits<=0 || motion_x_forw_c==0)
  1586.                 delta = motion_x_forw_c;
  1587.             else {
  1588.                 motion_x_forw_r = bits.get(forw_vector_bits)+1;
  1589.  
  1590.                 if (motion_x_forw_c<0)
  1591.                     delta = -(((-motion_x_forw_c-1)<<forw_vector_bits) + motion_x_forw_r);
  1592.                 else
  1593.                     delta = ((motion_x_forw_c-1)<<forw_vector_bits) + motion_x_forw_r;
  1594.             }
  1595.             forw_vector_x = (((forw_vector_x + delta) & forw_vector_mask) + forw_vector_extend) ^ forw_vector_extend;
  1596.  
  1597.             motion_y_forw_c = mpeg_get_motion_component();
  1598.  
  1599.             if ((signed char)forw_vector_bits<=0 || motion_y_forw_c==0)
  1600.                 delta = motion_y_forw_c;
  1601.             else {
  1602.                 motion_y_forw_r = bits.get(forw_vector_bits)+1;
  1603.  
  1604.                 if (motion_y_forw_c<0)
  1605.                     delta = -(((-motion_y_forw_c-1)<<forw_vector_bits) + motion_y_forw_r);
  1606.                 else
  1607.                     delta = ((motion_y_forw_c-1)<<forw_vector_bits) + motion_y_forw_r;
  1608.             }
  1609.             forw_vector_y = (((forw_vector_y + delta) & forw_vector_mask) + forw_vector_extend) ^ forw_vector_extend;
  1610.                 
  1611.             // grab the referred area into "pel1"
  1612.  
  1613. //_RPT4(0,"(%d,%d) copy motion vector (%+d,%+d)\n", pos_x, pos_y, forw_vector_x, forw_vector_y);
  1614.  
  1615. //            video_copy_forward_prediction(dstY, dstU, dstV, pos_x, pos_y);
  1616.         } else { // (only) in P_TYPE the motion vector is to be reset. 
  1617.             forw_vector_x = forw_vector_y = 0;
  1618. //_RPT2(0,"(%d,%d) reset motion vector\n", pos_x, pos_y);
  1619.             video_copy_forward(pos_x, pos_y);
  1620.         }
  1621.  
  1622.         if ((macro_block_flags & MBF_PATTERN)) {
  1623. #if 0
  1624.             long v = bits.peek(9)*2;
  1625.  
  1626.             cbp = mpeg_block_pattern_decode[v+0];
  1627.             bits.skip(mpeg_block_pattern_decode[v+1]);
  1628. #else
  1629.             long v = bits.peek(9);
  1630.  
  1631.             if (v >= 128) {
  1632.                 v>>=4;
  1633.                 cbp = mpeg_block_pattern_decode0[v*2+0-16];
  1634.                 bits.skip(mpeg_block_pattern_decode0[v*2+1-16]);
  1635.             } else {
  1636.                 cbp = mpeg_block_pattern_decode1[v*2+0];
  1637.                 bits.skip(mpeg_block_pattern_decode1[v*2+1]);
  1638.             }
  1639. #endif
  1640.         }
  1641.  
  1642.         if (macro_block_flags & MBF_FORWARD)
  1643.             video_copy_forward_prediction(pos_x, pos_y, false);
  1644.  
  1645.         if (cbp & 0x20) decode_mblock_Y(dstY);
  1646.         if (cbp & 0x10) decode_mblock_Y(dstY + 8);
  1647.         if (cbp & 0x08) decode_mblock_Y(dstY + y_pitch*8);
  1648.         if (cbp & 0x04) decode_mblock_Y(dstY + y_pitch*8 + 8);
  1649.  
  1650.         if (macro_block_flags & MBF_FORWARD)
  1651.             video_copy_forward_prediction(pos_x, pos_y, true);
  1652.  
  1653.         if (cbp & 0x02) decode_mblock_UV(dstU, dct_dc_u_past);
  1654.         if (cbp & 0x01) decode_mblock_UV(dstV, dct_dc_v_past);
  1655.  
  1656.         if (!(macro_block_flags & MBF_INTRA))
  1657.             dct_dc_y_past = dct_dc_u_past = dct_dc_v_past = MIDVAL;
  1658.  
  1659.         is_first_block=FALSE;
  1660.  
  1661. #ifdef STATISTICS
  1662.         if (macro_block_flags & MBF_PATTERN)
  1663.             stats.coded_block_pattern++;
  1664. #endif
  1665.     } while(!bits.next(23,0));
  1666. }
  1667.  
  1668. static void video_process_picture_slice_B(char *ptr, int type) {
  1669.     BOOL is_first_block = TRUE;
  1670.     long pos_x, pos_y;
  1671.  
  1672.     pos_y = type-1;
  1673.     pos_x = -1;
  1674.  
  1675.     dstY = Y_dest + 16 *  y_pitch * pos_y - 16;
  1676.     dstU = U_dest +  8 * uv_pitch * pos_y - 8;
  1677.     dstV = V_dest +  8 * uv_pitch * pos_y - 8;
  1678.  
  1679.     do {
  1680.         int inc = 0;
  1681.         signed char cbp = 0x3f;
  1682.         int i;
  1683.  
  1684.         // 00000001111 (00F) -> padding
  1685.         // 00000001000 (008) -> skip 33 more
  1686.         // 1 -> skip 1
  1687.  
  1688.         i = bits.peek(11);
  1689.         while(i == 0xf) {
  1690.             bits.skip(11);
  1691.             i = bits.peek(11);
  1692.         }
  1693.         while(i == 0x8) {
  1694.             bits.skip(11);
  1695.             i = bits.peek(11);
  1696.             inc += 33;
  1697.         }
  1698.         
  1699.         if (i&0x400) {
  1700.             bits.skip();
  1701.             ++inc;
  1702.         } else if (i>=96) {
  1703.             i >>= 4;
  1704.             bits.skip8(mpeg_macro_block_inc_decode2[i*2+1-12]);
  1705.             inc += mpeg_macro_block_inc_decode2[i*2+0-12];
  1706.         } else {
  1707.             bits.skip8(mpeg_macro_block_inc_decode[i*2+1]);
  1708.             inc += mpeg_macro_block_inc_decode[i*2+0];
  1709.         }
  1710.  
  1711.         if (inc > 1) {
  1712.             dct_dc_y_past = dct_dc_u_past = dct_dc_v_past = MIDVAL;
  1713.  
  1714.             if (!is_first_block) {
  1715.                 for(i=1; i<inc; i++) {
  1716.                     ++pos_x;
  1717.                     dstY += 16;
  1718.                     dstU += 8;
  1719.                     dstV += 8;
  1720.  
  1721.                     if(pos_x >= mbWidth) {
  1722.                         pos_x-=mbWidth;
  1723.                         pos_y++;
  1724.                         if (pos_y >= mbHeight)
  1725.                             return;
  1726.                         dstY += y_modulo;
  1727.                         dstU += uv_modulo;
  1728.                         dstV += uv_modulo;
  1729.                     }
  1730.  
  1731.                     if ((macro_block_flags & MBF_FORWARD)) {
  1732.                         video_copy_forward_prediction(
  1733.                             pos_x, pos_y, false);
  1734.  
  1735.                         if ((macro_block_flags & MBF_BACKWARD))
  1736.                             video_add_backward_prediction(
  1737.                                 pos_x, pos_y, false);
  1738.                     } else if ((macro_block_flags & MBF_BACKWARD)) {
  1739.                         video_copy_backward_prediction(
  1740.                             pos_x, pos_y, false);
  1741.                     }
  1742.                     if ((macro_block_flags & MBF_FORWARD)) {
  1743.                         video_copy_forward_prediction(
  1744.                             pos_x, pos_y, true);
  1745.  
  1746.                         if ((macro_block_flags & MBF_BACKWARD))
  1747.                             video_add_backward_prediction(
  1748.                                 pos_x, pos_y, true);
  1749.                     } else if ((macro_block_flags & MBF_BACKWARD)) {
  1750.                         video_copy_backward_prediction(
  1751.                             pos_x, pos_y, true);
  1752.                     }
  1753.                 }
  1754.             } else {
  1755.                 pos_x += inc-1;
  1756.                 dstY += 16*(inc-1);
  1757.                 dstU += 8*(inc-1);
  1758.                 dstV += 8*(inc-1);
  1759.             }
  1760.         }
  1761.  
  1762.         ++pos_x;
  1763.  
  1764.         while (pos_x >= mbWidth) {
  1765.             pos_x -= mbWidth;
  1766.             ++pos_y;
  1767.             if (pos_y >= mbHeight)
  1768.                 return;
  1769.  
  1770.             dstY += y_modulo;
  1771.             dstU += uv_modulo;
  1772.             dstV += uv_modulo;
  1773.         }
  1774.  
  1775.         dstY += 16;
  1776.         dstU += 8;
  1777.         dstV += 8;
  1778.  
  1779.         _ASSERT(dstY >= Y_dest);
  1780.         _ASSERT(dstY <= Y_dest + y_pitch * 16 * (mbHeight-1) + 16*(mbWidth-1));
  1781.  
  1782.         {
  1783.             long v=bits.peek(6);
  1784.  
  1785.             if (v>=32) {
  1786.                 macro_block_flags = MBF_FORWARD | MBF_BACKWARD;
  1787.                 if (v>=48)
  1788.                     macro_block_flags = MBF_FORWARD | MBF_BACKWARD | MBF_PATTERN;
  1789.  
  1790.                 bits.skip8(2);
  1791.             } else {
  1792.                 macro_block_flags = mpeg_b_type_mb_type_decode[v*2];
  1793.                 bits.skip8(mpeg_b_type_mb_type_decode[v*2+1]);
  1794.             }
  1795.         }
  1796.  
  1797.  
  1798.         if (!(macro_block_flags & MBF_INTRA)) {
  1799.             dct_dc_y_past = dct_dc_u_past = dct_dc_v_past = MIDVAL;
  1800.             cbp = 0;
  1801.         }
  1802.  
  1803.         if ((macro_block_flags & MBF_NEW_QUANT)) {
  1804.             int quant_scale = bits.get8(5);
  1805.             intramatrix = intramatrices[quant_scale];
  1806.             nonintramatrix = nonintramatrices[quant_scale];
  1807.         }
  1808.  
  1809.         if ((macro_block_flags & MBF_FORWARD)) {                // motion vector for forward prediction exists
  1810.             int motion_x_forw_c, motion_y_forw_c;
  1811.             int motion_x_forw_r, motion_y_forw_r;
  1812.             int delta;
  1813.  
  1814.             motion_x_forw_c = mpeg_get_motion_component();
  1815.  
  1816.             // according to this information the motion vector must be decoded
  1817.  
  1818.             if ((signed char)forw_vector_bits<=0 || motion_x_forw_c==0)
  1819.                 delta = motion_x_forw_c;
  1820.             else {
  1821.                 motion_x_forw_r = bits.get(forw_vector_bits)+1;
  1822.  
  1823.                 if (motion_x_forw_c<0)
  1824.                     delta = -(((-motion_x_forw_c-1)<<forw_vector_bits) + motion_x_forw_r);
  1825.                 else
  1826.                     delta = ((motion_x_forw_c-1)<<forw_vector_bits) + motion_x_forw_r;
  1827.             }
  1828.             forw_vector_x = (((forw_vector_x + delta) & forw_vector_mask) + forw_vector_extend) ^ forw_vector_extend;
  1829.  
  1830.             motion_y_forw_c = mpeg_get_motion_component();
  1831.  
  1832.             if ((signed char)forw_vector_bits<=0 || motion_y_forw_c==0)
  1833.                 delta = motion_y_forw_c;
  1834.             else {
  1835.                 motion_y_forw_r = bits.get(forw_vector_bits)+1;
  1836.  
  1837.                 if (motion_y_forw_c<0)
  1838.                     delta = -(((-motion_y_forw_c-1)<<forw_vector_bits) + motion_y_forw_r);
  1839.                 else
  1840.                     delta = ((motion_y_forw_c-1)<<forw_vector_bits) + motion_y_forw_r;
  1841.             }
  1842.             forw_vector_y = (((forw_vector_y + delta) & forw_vector_mask) + forw_vector_extend) ^ forw_vector_extend;
  1843.  
  1844.         }
  1845.  
  1846.         if ((macro_block_flags & MBF_BACKWARD)) {
  1847.             int motion_x_back_c, motion_y_back_c;
  1848.             int motion_x_back_r, motion_y_back_r;
  1849.             int delta;
  1850.  
  1851.             motion_x_back_c = mpeg_get_motion_component();
  1852.  
  1853.             // according to this information the motion vector must be decoded
  1854.  
  1855.             if ((signed char)back_vector_bits<=0 || motion_x_back_c==0)
  1856.                 delta = motion_x_back_c;
  1857.             else {
  1858.                 motion_x_back_r = bits.get(back_vector_bits)+1;
  1859.  
  1860.                 if (motion_x_back_c<0)
  1861.                     delta = -(((-motion_x_back_c-1)<<back_vector_bits) + motion_x_back_r);
  1862.                 else
  1863.                     delta = ((motion_x_back_c-1)<<back_vector_bits) + motion_x_back_r;
  1864.             }
  1865.             back_vector_x = (((back_vector_x + delta) & back_vector_mask) + back_vector_extend) ^ back_vector_extend;
  1866.  
  1867.             motion_y_back_c = mpeg_get_motion_component();
  1868.  
  1869.             if ((signed char)back_vector_bits<=0 || motion_y_back_c==0)
  1870.                 delta = motion_y_back_c;
  1871.             else {
  1872.                 motion_y_back_r = bits.get(back_vector_bits)+1;
  1873.  
  1874.                 if (motion_y_back_c<0)
  1875.                     delta = -(((-motion_y_back_c-1)<<back_vector_bits) + motion_y_back_r);
  1876.                 else
  1877.                     delta = ((motion_y_back_c-1)<<back_vector_bits) + motion_y_back_r;
  1878.             }
  1879.             back_vector_y = (((back_vector_y + delta) & back_vector_mask) + back_vector_extend) ^ back_vector_extend;
  1880.                 
  1881.         }
  1882.  
  1883.         if ((macro_block_flags & MBF_PATTERN)) {
  1884.             long v = bits.peek(9);
  1885.  
  1886.             if (v >= 128) {
  1887.                 v>>=4;
  1888.                 cbp = mpeg_block_pattern_decode0[v*2+0-16];
  1889.                 bits.skip8(mpeg_block_pattern_decode0[v*2+1-16]);
  1890.             } else {
  1891.                 cbp = mpeg_block_pattern_decode1[v*2+0];
  1892.                 bits.skip(mpeg_block_pattern_decode1[v*2+1]);
  1893.             }
  1894.         }
  1895.  
  1896.         if (macro_block_flags & MBF_FORWARD) {
  1897.             video_copy_forward_prediction(pos_x, pos_y, false);
  1898.             if (macro_block_flags & MBF_BACKWARD)
  1899.                 video_add_backward_prediction(pos_x, pos_y, false);
  1900.         } else if (macro_block_flags & MBF_BACKWARD)
  1901.             video_copy_backward_prediction(pos_x, pos_y, false);
  1902.  
  1903.         if (cbp & 0x20) decode_mblock_Y(dstY);
  1904.         if (cbp & 0x10) decode_mblock_Y(dstY + 8);
  1905.         if (cbp & 0x08) decode_mblock_Y(dstY + y_pitch*8);
  1906.         if (cbp & 0x04) decode_mblock_Y(dstY + y_pitch*8 + 8);
  1907.  
  1908.         if (macro_block_flags & MBF_FORWARD) {
  1909.             video_copy_forward_prediction(pos_x, pos_y, true);
  1910.             if (macro_block_flags & MBF_BACKWARD)
  1911.                 video_add_backward_prediction(pos_x, pos_y, true);
  1912.         } else if (macro_block_flags & MBF_BACKWARD)
  1913.             video_copy_backward_prediction(pos_x, pos_y, true);
  1914.  
  1915.         if (cbp & 0x02) decode_mblock_UV(dstU, dct_dc_u_past);
  1916.         if (cbp & 0x01) decode_mblock_UV(dstV, dct_dc_v_past);
  1917.  
  1918.         if (macro_block_flags & MBF_INTRA)
  1919.             forw_vector_x = forw_vector_y = back_vector_x = back_vector_y = 0;            
  1920.         else
  1921.             dct_dc_y_past = dct_dc_u_past = dct_dc_v_past = MIDVAL;
  1922.  
  1923.         is_first_block=FALSE;
  1924.  
  1925. #ifdef STATISTICS
  1926.         if (macro_block_flags & MBF_PATTERN)
  1927.             stats.coded_block_pattern++;
  1928. #endif
  1929.  
  1930.     } while(!bits.next(23,0));
  1931. }
  1932.  
  1933. static void video_process_picture_slice(char *ptr, int type) {
  1934.     int quant_scale;
  1935.  
  1936.     bits = CMemoryBitInput(ptr);
  1937.  
  1938.     dct_dc_y_past = dct_dc_u_past = dct_dc_v_past = MIDVAL;
  1939.  
  1940.     forw_vector_x = forw_vector_y = 0;
  1941.     back_vector_x = back_vector_y = 0;
  1942.  
  1943.     quant_scale = bits.get(5);
  1944.     intramatrix = intramatrices[quant_scale];
  1945.     nonintramatrix = nonintramatrices[quant_scale];
  1946.  
  1947.     memset(dct_coeff, 0, sizeof dct_coeff);
  1948.  
  1949.     while(bits.get())
  1950.         bits.skip(8);
  1951.  
  1952.     if (type > mbHeight)
  1953.         return;
  1954.  
  1955.     switch(frame_type) {
  1956.     case I_FRAME:    video_process_picture_slice_I(ptr, type); break;
  1957.     case P_FRAME:    video_process_picture_slice_P(ptr, type); break;
  1958.     case B_FRAME:    video_process_picture_slice_B(ptr, type); break;
  1959.     }
  1960. }
  1961.  
  1962. //////////////////////////////////////////////////////////////
  1963.  
  1964. extern "C" void asm_YUVtoRGB32_row(
  1965.         unsigned long *ARGB1_pointer,
  1966.         unsigned long *ARGB2_pointer,
  1967.         YUVPixel *Y1_pointer,
  1968.         YUVPixel *Y2_pointer,
  1969.         YUVPixel *U_pointer,
  1970.         YUVPixel *V_pointer,
  1971.         long width
  1972.         );
  1973.  
  1974. extern "C" void asm_YUVtoRGB24_row(
  1975.         unsigned long *ARGB1_pointer,
  1976.         unsigned long *ARGB2_pointer,
  1977.         YUVPixel *Y1_pointer,
  1978.         YUVPixel *Y2_pointer,
  1979.         YUVPixel *U_pointer,
  1980.         YUVPixel *V_pointer,
  1981.         long width
  1982.         );
  1983.  
  1984. extern "C" void asm_YUVtoRGB16_row(
  1985.         unsigned long *ARGB1_pointer,
  1986.         unsigned long *ARGB2_pointer,
  1987.         YUVPixel *Y1_pointer,
  1988.         YUVPixel *Y2_pointer,
  1989.         YUVPixel *U_pointer,
  1990.         YUVPixel *V_pointer,
  1991.         long width
  1992.         );
  1993.  
  1994. static void YUVToRGB32(YUVPixel *Y_ptr, YUVPixel *U_ptr, YUVPixel *V_ptr, unsigned char *dst, long bpr, long w, long h) {
  1995.     dst = dst + bpr * (2*h - 2);
  1996.  
  1997.     do {
  1998.         asm_YUVtoRGB32_row(
  1999.                 (unsigned long *)(dst + bpr),
  2000.                 (unsigned long *)dst,
  2001.                 Y_ptr,
  2002.                 Y_ptr + y_pitch,
  2003.                 U_ptr,
  2004.                 V_ptr,
  2005.                 w);
  2006.  
  2007.         dst = dst - 2*bpr;
  2008.         Y_ptr = Y_ptr + 2*y_pitch;
  2009.         U_ptr = U_ptr + uv_pitch;
  2010.         V_ptr = V_ptr + uv_pitch;
  2011.     } while(--h);
  2012.  
  2013.     if (MMX_enabled)
  2014.         __asm emms
  2015.  
  2016.     if (ISSE_enabled)
  2017.         __asm sfence
  2018. }
  2019.  
  2020. static void YUVToRGB24(YUVPixel *Y_ptr, YUVPixel *U_ptr, YUVPixel *V_ptr, unsigned char *dst, long bpr, long w, long h) {
  2021.     dst = dst + bpr * (2*h - 2);
  2022.  
  2023.     do {
  2024.         asm_YUVtoRGB24_row(
  2025.                 (unsigned long *)(dst + bpr),
  2026.                 (unsigned long *)dst,
  2027.                 Y_ptr,
  2028.                 Y_ptr + y_pitch,
  2029.                 U_ptr,
  2030.                 V_ptr,
  2031.                 w);
  2032.  
  2033.         dst = dst - 2*bpr;
  2034.         Y_ptr = Y_ptr + 2*y_pitch;
  2035.         U_ptr = U_ptr + uv_pitch;
  2036.         V_ptr = V_ptr + uv_pitch;
  2037.     } while(--h);
  2038.  
  2039.     if (MMX_enabled)
  2040.         __asm emms
  2041.  
  2042.     if (ISSE_enabled)
  2043.         __asm sfence
  2044. }
  2045. static void YUVToRGB16(YUVPixel *Y_ptr, YUVPixel *U_ptr, YUVPixel *V_ptr, unsigned char *dst, long bpr, long w, long h) {
  2046.     dst = dst + bpr * (2*h - 2);
  2047.  
  2048.     do {
  2049.         asm_YUVtoRGB16_row(
  2050.                 (unsigned long *)(dst + bpr),
  2051.                 (unsigned long *)dst,
  2052.                 Y_ptr,
  2053.                 Y_ptr + y_pitch,
  2054.                 U_ptr,
  2055.                 V_ptr,
  2056.                 w);
  2057.  
  2058.         dst = dst - 2*bpr;
  2059.         Y_ptr = Y_ptr + 2*y_pitch;
  2060.         U_ptr = U_ptr + uv_pitch;
  2061.         V_ptr = V_ptr + uv_pitch;
  2062.     } while(--h);
  2063.  
  2064.     if (MMX_enabled)
  2065.         __asm emms
  2066.  
  2067.     if (ISSE_enabled)
  2068.         __asm sfence
  2069. }
  2070.  
  2071. static void __declspec(naked) YUVtoUYVY16_MMX(
  2072.                 YUVPixel *Y_ptr,        // [esp+4+16]
  2073.                 YUVPixel *U_ptr,        // [esp+8+16]
  2074.                 YUVPixel *V_ptr,        // [esp+12+16]
  2075.                 unsigned char *dst,        // [esp+16+16]
  2076.                 long bpr,                // [esp+20+16]
  2077.                 long w,                    // [esp+24+16]
  2078.                 long h) {                // [esp+28+16]
  2079.  
  2080.     __asm {
  2081.         push        ebp
  2082.         push        edi
  2083.         push        esi
  2084.         push        ebx
  2085.  
  2086.         mov            edx,[esp+24+16]            ;load width (mult of 8)
  2087.  
  2088.         mov            ebx,[esp+8+16]            ;load source U ptr
  2089.         mov            ecx,[esp+12+16]            ;load source V ptr
  2090.         mov            eax,[esp+4+16]            ;load source Y ptr
  2091.         mov            edi,[esp+16+16]            ;load destination ptr
  2092.         mov            esi,[esp+20+16]            ;load destination pitch
  2093.         mov            ebp,[esp+28+16]            ;load height
  2094.  
  2095.         lea            ebx,[ebx+edx]            ;bias pointers
  2096.         lea            ecx,[ecx+edx]            ;(we count from -n to 0)
  2097.         lea            eax,[eax+edx*2]
  2098.         lea            edi,[edi+edx*4]
  2099.  
  2100.         neg            edx
  2101.         mov            [esp+24+16],edx
  2102. xyloop:
  2103.         movq        mm0,[ebx+edx]            ;U0-U7
  2104.  
  2105.         movq        mm7,[ecx+edx]            ;V0-V7
  2106.         movq        mm2,mm0                    ;U0-U7
  2107.  
  2108.         movq        mm4,[eax+edx*2]
  2109.         punpcklbw    mm0,mm7                    ;[V3][U3][V2][U2][V1][U1][V0][U0]
  2110.  
  2111.         movq        mm5,[eax+edx*2+8]
  2112.         punpckhbw    mm2,mm7                    ;[V7][U7][V6][U6][V5][U5][V4][U4]
  2113.  
  2114.         movq        mm1,mm0
  2115.         punpcklbw    mm0,mm4                    ;[Y3][V1][Y2][U1][Y1][V0][Y0][U0]
  2116.  
  2117.         punpckhbw    mm1,mm4                    ;[Y7][V3][Y6][U3][Y5][V2][Y4][U2]
  2118.         movq        mm3,mm2
  2119.  
  2120.         movq        [edi+edx*4+ 0],mm0
  2121.         punpcklbw    mm2,mm5                    ;[YB][V5][YA][U5][Y9][V4][Y8][U4]
  2122.  
  2123.         movq        [edi+edx*4+ 8],mm1
  2124.         punpckhbw    mm3,mm5                    ;[YF][V7][YE][U7][YD][V6][YC][U6]
  2125.  
  2126.         movq        [edi+edx*4+16],mm2
  2127.  
  2128.         movq        [edi+edx*4+24],mm3
  2129.  
  2130.         add            edx,8
  2131.         jnc            xyloop
  2132.  
  2133.         mov            edx,[esp+24+16]            ;reload width counter
  2134.  
  2135.         test        ebp,1                    ;update U/V row every other row only
  2136.         jz            oddline
  2137.  
  2138.         sub            ebx,edx                    ;advance U pointer
  2139.         sub            ecx,edx                    ;advance V pointer
  2140.  
  2141. oddline:
  2142.         sub            eax,edx                    ;advance Y pointer
  2143.         sub            eax,edx                    ;advance Y pointer
  2144.  
  2145.         add            edi,esi                    ;advance dest ptr
  2146.  
  2147.         dec            ebp
  2148.         jne            xyloop
  2149.  
  2150.         pop            ebx
  2151.         pop            esi
  2152.         pop            edi
  2153.         pop            ebp
  2154.         emms
  2155.         ret
  2156.     }
  2157. }
  2158.  
  2159. static void YUVToUYVY16(YUVPixel *Y_ptr, YUVPixel *U_ptr, YUVPixel *V_ptr, unsigned char *dst, long bpr, long w, long h) {
  2160.     if (MMX_enabled) {
  2161.         YUVtoUYVY16_MMX(Y_ptr, U_ptr, V_ptr, dst, bpr, w, h*2);
  2162.         return;
  2163.     }
  2164.  
  2165.     do {
  2166.         int wt;
  2167.  
  2168.         wt = w/8;
  2169.         do {
  2170.             char z = *dst;
  2171.             char z2 = dst[31];
  2172.             *dst++ = *U_ptr++;
  2173.             *dst++ = *Y_ptr++;
  2174.             *dst++ = *V_ptr++;
  2175.             *dst++ = *Y_ptr++;
  2176.             *dst++ = *U_ptr++;
  2177.             *dst++ = *Y_ptr++;
  2178.             *dst++ = *V_ptr++;
  2179.             *dst++ = *Y_ptr++;
  2180.             *dst++ = *U_ptr++;
  2181.             *dst++ = *Y_ptr++;
  2182.             *dst++ = *V_ptr++;
  2183.             *dst++ = *Y_ptr++;
  2184.             *dst++ = *U_ptr++;
  2185.             *dst++ = *Y_ptr++;
  2186.             *dst++ = *V_ptr++;
  2187.             *dst++ = *Y_ptr++;
  2188.             *dst++ = *U_ptr++;
  2189.             *dst++ = *Y_ptr++;
  2190.             *dst++ = *V_ptr++;
  2191.             *dst++ = *Y_ptr++;
  2192.             *dst++ = *U_ptr++;
  2193.             *dst++ = *Y_ptr++;
  2194.             *dst++ = *V_ptr++;
  2195.             *dst++ = *Y_ptr++;
  2196.             *dst++ = *U_ptr++;
  2197.             *dst++ = *Y_ptr++;
  2198.             *dst++ = *V_ptr++;
  2199.             *dst++ = *Y_ptr++;
  2200.             *dst++ = *U_ptr++;
  2201.             *dst++ = *Y_ptr++;
  2202.             *dst++ = *V_ptr++;
  2203.             *dst++ = *Y_ptr++;
  2204.         } while(--wt);
  2205.  
  2206.         U_ptr = U_ptr - uv_pitch;
  2207.         V_ptr = V_ptr - uv_pitch;
  2208.         
  2209.         wt = w/8;
  2210.         do {
  2211.             char z = *dst;
  2212.             char z2 = dst[31];
  2213.             *dst++ = *U_ptr++;
  2214.             *dst++ = *Y_ptr++;
  2215.             *dst++ = *V_ptr++;
  2216.             *dst++ = *Y_ptr++;
  2217.             *dst++ = *U_ptr++;
  2218.             *dst++ = *Y_ptr++;
  2219.             *dst++ = *V_ptr++;
  2220.             *dst++ = *Y_ptr++;
  2221.             *dst++ = *U_ptr++;
  2222.             *dst++ = *Y_ptr++;
  2223.             *dst++ = *V_ptr++;
  2224.             *dst++ = *Y_ptr++;
  2225.             *dst++ = *U_ptr++;
  2226.             *dst++ = *Y_ptr++;
  2227.             *dst++ = *V_ptr++;
  2228.             *dst++ = *Y_ptr++;
  2229.             *dst++ = *U_ptr++;
  2230.             *dst++ = *Y_ptr++;
  2231.             *dst++ = *V_ptr++;
  2232.             *dst++ = *Y_ptr++;
  2233.             *dst++ = *U_ptr++;
  2234.             *dst++ = *Y_ptr++;
  2235.             *dst++ = *V_ptr++;
  2236.             *dst++ = *Y_ptr++;
  2237.             *dst++ = *U_ptr++;
  2238.             *dst++ = *Y_ptr++;
  2239.             *dst++ = *V_ptr++;
  2240.             *dst++ = *Y_ptr++;
  2241.             *dst++ = *U_ptr++;
  2242.             *dst++ = *Y_ptr++;
  2243.             *dst++ = *V_ptr++;
  2244.             *dst++ = *Y_ptr++;
  2245.         } while(--wt);
  2246.  
  2247.     } while(--h);
  2248. }
  2249.  
  2250. static void __declspec(naked) YUVtoYUY2_MMX(
  2251.                 YUVPixel *Y_ptr,        // [esp+4+16]
  2252.                 YUVPixel *U_ptr,        // [esp+8+16]
  2253.                 YUVPixel *V_ptr,        // [esp+12+16]
  2254.                 unsigned char *dst,        // [esp+16+16]
  2255.                 long bpr,                // [esp+20+16]
  2256.                 long w,                    // [esp+24+16]
  2257.                 long h) {                // [esp+28+16]
  2258.  
  2259.     __asm {
  2260.         push        ebp
  2261.         push        edi
  2262.         push        esi
  2263.         push        ebx
  2264.  
  2265.         mov            edx,[esp+24+16]            ;multiply width by 8
  2266.  
  2267.         mov            ebx,[esp+8+16]            ;load source U ptr
  2268.         mov            ecx,[esp+12+16]            ;load source V ptr
  2269.         mov            eax,[esp+4+16]            ;load source Y ptr
  2270.         mov            edi,[esp+16+16]            ;load destination ptr
  2271.         mov            esi,[esp+20+16]            ;load destination pitch
  2272.         mov            ebp,[esp+28+16]            ;load height
  2273.  
  2274.         lea            ebx,[ebx+edx]            ;bias pointers
  2275.         lea            ecx,[ecx+edx]            ;(we count from -n to 0)
  2276.         lea            eax,[eax+edx*2]
  2277.         lea            edi,[edi+edx*4]
  2278.  
  2279.         neg            edx
  2280.         mov            [esp+24+16],edx
  2281. xyloop:
  2282.         movq        mm0,[ebx+edx]            ;U0-U7
  2283.  
  2284.         movq        mm7,[ecx+edx]            ;V0-V7
  2285.         movq        mm1,mm0                    ;U0-U7
  2286.  
  2287.         movq        mm2,[eax+edx*2]            ;Y0-Y7
  2288.         punpcklbw    mm0,mm7                    ;[V3][U3][V2][U2][V1][U1][V0][U0]
  2289.  
  2290.         movq        mm4,[eax+edx*2+8]        ;Y8-YF
  2291.         punpckhbw    mm1,mm7                    ;[V7][U7][V6][U6][V5][U5][V4][U4]
  2292.  
  2293.         movq        mm3,mm2
  2294.         punpcklbw    mm2,mm0                    ;[V1][Y3][U1][Y2][V0][Y1][U0][Y0]
  2295.  
  2296.         movq        mm5,mm4
  2297.         punpckhbw    mm3,mm0                    ;[V3][Y7][U3][Y6][V2][Y5][U2][Y4]
  2298.  
  2299.         movq        [edi+edx*4+ 0],mm2
  2300.         punpcklbw    mm4,mm1                    ;[V5][YB][U5][YA][V4][Y9][U4][Y8]
  2301.  
  2302.         movq        [edi+edx*4+ 8],mm3
  2303.         punpckhbw    mm5,mm1                    ;[V7][YF][U7][YE][V6][YD][U6][YC]
  2304.  
  2305.         movq        [edi+edx*4+16],mm4
  2306.  
  2307.         movq        [edi+edx*4+24],mm5
  2308.         add            edx,8
  2309.  
  2310.         jnc            xyloop
  2311.  
  2312.         mov            edx,[esp+24+16]            ;reload width counter
  2313.  
  2314.         test        ebp,1                    ;update U/V row every other row only
  2315.         jz            oddline
  2316.  
  2317.         sub            ebx,edx                    ;advance U pointer
  2318.         sub            ecx,edx                    ;advance V pointer
  2319.  
  2320. oddline:
  2321.         sub            eax,edx                    ;advance Y pointer
  2322.         sub            eax,edx                    ;advance Y pointer
  2323.  
  2324.         add            edi,esi                    ;advance dest ptr
  2325.  
  2326.         dec            ebp
  2327.         jne            xyloop
  2328.  
  2329.         pop            ebx
  2330.         pop            esi
  2331.         pop            edi
  2332.         pop            ebp
  2333.         emms
  2334.         ret
  2335.     }
  2336. }
  2337.  
  2338. static void YUVToYUY216(YUVPixel *Y_ptr, YUVPixel *U_ptr, YUVPixel *V_ptr, unsigned char *dst, long bpr, long w, long h) {
  2339.  
  2340.     if (MMX_enabled) {
  2341.         YUVtoYUY2_MMX(Y_ptr, U_ptr, V_ptr, dst, bpr, w, h*2);
  2342.         return;
  2343.     }
  2344.  
  2345.     do {
  2346.         int wt;
  2347.  
  2348.         wt = w/8;
  2349.         do {
  2350.             char z = *dst;
  2351.             *dst++ = *Y_ptr++;
  2352.             *dst++ = *U_ptr++;
  2353.             *dst++ = *Y_ptr++;
  2354.             *dst++ = *V_ptr++;
  2355.             *dst++ = *Y_ptr++;
  2356.             *dst++ = *U_ptr++;
  2357.             *dst++ = *Y_ptr++;
  2358.             *dst++ = *V_ptr++;
  2359.             *dst++ = *Y_ptr++;
  2360.             *dst++ = *U_ptr++;
  2361.             *dst++ = *Y_ptr++;
  2362.             *dst++ = *V_ptr++;
  2363.             *dst++ = *Y_ptr++;
  2364.             *dst++ = *U_ptr++;
  2365.             *dst++ = *Y_ptr++;
  2366.             *dst++ = *V_ptr++;
  2367.             *dst++ = *Y_ptr++;
  2368.             *dst++ = *U_ptr++;
  2369.             *dst++ = *Y_ptr++;
  2370.             *dst++ = *V_ptr++;
  2371.             *dst++ = *Y_ptr++;
  2372.             *dst++ = *U_ptr++;
  2373.             *dst++ = *Y_ptr++;
  2374.             *dst++ = *V_ptr++;
  2375.             *dst++ = *Y_ptr++;
  2376.             *dst++ = *U_ptr++;
  2377.             *dst++ = *Y_ptr++;
  2378.             *dst++ = *V_ptr++;
  2379.             *dst++ = *Y_ptr++;
  2380.             *dst++ = *U_ptr++;
  2381.             *dst++ = *Y_ptr++;
  2382.             *dst++ = *V_ptr++;
  2383.         } while(--wt);
  2384.  
  2385.         U_ptr = U_ptr - uv_pitch;
  2386.         V_ptr = V_ptr - uv_pitch;
  2387.         
  2388.         wt = w/8;
  2389.         do {
  2390.             char z = *dst;
  2391.             *dst++ = *Y_ptr++;
  2392.             *dst++ = *U_ptr++;
  2393.             *dst++ = *Y_ptr++;
  2394.             *dst++ = *V_ptr++;
  2395.             *dst++ = *Y_ptr++;
  2396.             *dst++ = *U_ptr++;
  2397.             *dst++ = *Y_ptr++;
  2398.             *dst++ = *V_ptr++;
  2399.             *dst++ = *Y_ptr++;
  2400.             *dst++ = *U_ptr++;
  2401.             *dst++ = *Y_ptr++;
  2402.             *dst++ = *V_ptr++;
  2403.             *dst++ = *Y_ptr++;
  2404.             *dst++ = *U_ptr++;
  2405.             *dst++ = *Y_ptr++;
  2406.             *dst++ = *V_ptr++;
  2407.             *dst++ = *Y_ptr++;
  2408.             *dst++ = *U_ptr++;
  2409.             *dst++ = *Y_ptr++;
  2410.             *dst++ = *V_ptr++;
  2411.             *dst++ = *Y_ptr++;
  2412.             *dst++ = *U_ptr++;
  2413.             *dst++ = *Y_ptr++;
  2414.             *dst++ = *V_ptr++;
  2415.             *dst++ = *Y_ptr++;
  2416.             *dst++ = *U_ptr++;
  2417.             *dst++ = *Y_ptr++;
  2418.             *dst++ = *V_ptr++;
  2419.             *dst++ = *Y_ptr++;
  2420.             *dst++ = *U_ptr++;
  2421.             *dst++ = *Y_ptr++;
  2422.             *dst++ = *V_ptr++;
  2423.         } while(--wt);
  2424.  
  2425.     } while(--h);
  2426. }
  2427.  
  2428. //////////////////////////////////////////////////////////////
  2429.  
  2430. #pragma warning(push)
  2431. #pragma warning(disable: 4799)        // function has no EMMS instruction
  2432.  
  2433. void video_copy_forward(int x_pos, int y_pos) {
  2434.     YUVPixel *Y_src, *U_src, *V_src;
  2435.  
  2436.     Y_src = Y_forw + 16*x_pos +  y_pitch*(16*y_pos);
  2437.     U_src = U_forw +  8*x_pos + uv_pitch*( 8*y_pos);
  2438.     V_src = V_forw +  8*x_pos + uv_pitch*( 8*y_pos);
  2439.  
  2440.     // luminance
  2441.  
  2442.     if (MMX_enabled)
  2443.         __asm {
  2444.             push esi
  2445.             push edi
  2446.             mov esi,y_pitch
  2447.  
  2448.             mov ecx,Y_src
  2449.             mov edx,dstY
  2450.             mov edi,8
  2451.  
  2452.         loop_Y_MMX:
  2453.             movq    mm0,[ecx]
  2454.             movq    mm1,[ecx+8]
  2455.             movq    [edx],mm0
  2456.             movq    mm2,[ecx+esi]
  2457.             movq    [edx+8],mm1
  2458.             movq    mm3,[ecx+esi+8]
  2459.             movq    [edx+esi],mm2
  2460.             movq    [edx+esi+8],mm3
  2461.             lea        ecx,[ecx+esi*2]
  2462.             dec        edi
  2463.             lea        edx,[edx+esi*2]
  2464.             jne        loop_Y_MMX
  2465.  
  2466.             mov ecx,U_src
  2467.             mov edx,dstU
  2468.             mov esi,uv_pitch
  2469.             mov edi,4
  2470.  
  2471.         loop_U_MMX:
  2472.             movq    mm0,[ecx]
  2473.             movq    mm1,[ecx+esi]
  2474.             movq    [edx],mm0
  2475.             movq    [edx+esi],mm1
  2476.             lea        ecx,[ecx+esi*2]
  2477.             dec        edi
  2478.             lea        edx,[edx+esi*2]
  2479.             jne        loop_U_MMX
  2480.  
  2481.             mov ecx,V_src
  2482.             mov edx,dstV
  2483.             mov edi,4
  2484.  
  2485.         loop_V_MMX:
  2486.             movq    mm0,[ecx]
  2487.             movq    mm1,[ecx+esi]
  2488.             movq    [edx],mm0
  2489.             movq    [edx+esi],mm1
  2490.             lea        ecx,[ecx+esi*2]
  2491.             dec        edi
  2492.             lea        edx,[edx+esi*2]
  2493.             jne        loop_V_MMX
  2494.  
  2495.             pop edi
  2496.             pop esi
  2497.         }
  2498.     else
  2499.         __asm {
  2500.             push esi
  2501.             push edi
  2502.             mov esi,y_pitch
  2503.  
  2504.             mov ecx,Y_src
  2505.             mov edx,dstY
  2506.             mov edi,16
  2507.  
  2508.         loop_Y:
  2509.             mov eax,[ecx]
  2510.             mov ebx,[ecx+4]
  2511.             mov [edx],eax
  2512.             mov [edx+4],ebx
  2513.  
  2514.             mov eax,[ecx+8]
  2515.             mov ebx,[ecx+12]
  2516.             mov [edx+8],eax
  2517.             mov [edx+12],ebx
  2518.  
  2519.             add ecx,esi
  2520.             add edx,esi
  2521.  
  2522.             dec edi
  2523.             jne loop_Y
  2524.  
  2525.             mov ecx,U_src
  2526.             mov edx,dstU
  2527.             mov esi,uv_pitch
  2528.             mov edi,8
  2529.  
  2530.         loop_U:
  2531.             mov eax,[ecx]
  2532.             mov ebx,[ecx+4]
  2533.             mov [edx],eax
  2534.             mov [edx+4],ebx
  2535.  
  2536.             add ecx,esi
  2537.             add edx,esi
  2538.  
  2539.             dec edi
  2540.             jne loop_U
  2541.  
  2542.             mov ecx,V_src
  2543.             mov edx,dstV
  2544.             mov edi,8
  2545.  
  2546.         loop_V:
  2547.             mov eax,[ecx]
  2548.             mov ebx,[ecx+4]
  2549.             mov [edx],eax
  2550.             mov [edx+4],ebx
  2551.  
  2552.             add ecx,esi
  2553.             add edx,esi
  2554.  
  2555.             dec edi
  2556.             jne loop_V
  2557.  
  2558.             pop edi
  2559.             pop esi
  2560.         }
  2561. }
  2562.  
  2563. #pragma warning(pop)
  2564.  
  2565. static void video_copy_forward_prediction(int x_pos, int y_pos, bool fchrom) {
  2566.     long vx = forw_vector_x;
  2567.     long vy = forw_vector_y;
  2568.     long vxY, vyY, vxC, vyC;
  2569.  
  2570.     if (forw_vector_full_pel) {
  2571.         vx <<= 1;
  2572.         vy <<= 1;
  2573.     }
  2574.  
  2575.     vxY = vx + 32*x_pos;
  2576.     vyY = vy + 32*y_pos;
  2577.     vxC = vx/2 + 16*x_pos;
  2578.     vyC = vy/2 + 16*y_pos;
  2579.  
  2580.     if (vxY<0 || vyY<0 || vxY>vector_limit_x || vyY>vector_limit_y)
  2581.         vxY = vyY = vxC = vyC = 0;
  2582.  
  2583.     if (!fchrom)
  2584.         video_copy_prediction_Y(Y_forw, dstY, vxY, vyY, y_pitch);
  2585.     else {
  2586.         video_copy_prediction_C(U_forw, dstU, vxC, vyC, uv_pitch);
  2587.         video_copy_prediction_C(V_forw, dstV, vxC, vyC, uv_pitch);
  2588.     }
  2589.  
  2590. }
  2591.  
  2592. static void video_copy_backward_prediction(int x_pos, int y_pos, bool fchrom) {
  2593.     long vx = back_vector_x;
  2594.     long vy = back_vector_y;
  2595.     long vxY, vyY, vxC, vyC;
  2596.  
  2597.     if (back_vector_full_pel) {
  2598.         vx <<= 1;
  2599.         vy <<= 1;
  2600.     }
  2601.  
  2602.     vxY = vx + 32*x_pos;
  2603.     vyY = vy + 32*y_pos;
  2604.     vxC = vx/2 + 16*x_pos;
  2605.     vyC = vy/2 + 16*y_pos;
  2606.  
  2607.     if (vxY<0 || vyY<0 || vxY>vector_limit_x || vyY>vector_limit_y)
  2608.         vxY = vyY = vxC = vyC = 0;
  2609.  
  2610.     if (!fchrom)
  2611.         video_copy_prediction_Y(Y_back, dstY, vxY, vyY, y_pitch);
  2612.     else {
  2613.         video_copy_prediction_C(U_back, dstU, vxC, vyC, uv_pitch);
  2614.         video_copy_prediction_C(V_back, dstV, vxC, vyC, uv_pitch);
  2615.     }
  2616. }
  2617.  
  2618. static void video_add_backward_prediction(int x_pos, int y_pos, bool fchrom) {
  2619.     long vx = back_vector_x;
  2620.     long vy = back_vector_y;
  2621.     long vxY, vyY, vxC, vyC;
  2622.  
  2623.     if (back_vector_full_pel) {
  2624.         vx <<= 1;
  2625.         vy <<= 1;
  2626.     }
  2627.  
  2628.     vxY = vx + 32*x_pos;
  2629.     vyY = vy + 32*y_pos;
  2630.     vxC = vx/2 + 16*x_pos;
  2631.     vyC = vy/2 + 16*y_pos;
  2632.  
  2633.     if (vxY<0 || vyY<0 || vxY>vector_limit_x || vyY>vector_limit_y)
  2634.         vxY = vyY = vxC = vyC = 0;
  2635.  
  2636.     if (!fchrom)
  2637.         video_add_prediction_Y(Y_back, dstY, vxY, vyY, y_pitch);
  2638.     else {
  2639.         video_add_prediction_C(U_back, dstU, vxC, vyC, uv_pitch);
  2640.         video_add_prediction_C(V_back, dstV, vxC, vyC, uv_pitch);
  2641.     }
  2642. }
  2643.  
  2644. ///////////////////////////////////////////////////////////////////////////
  2645.  
  2646. #if 0
  2647. #ifdef _DEBUG
  2648.  
  2649. class MPEGDecoderVerifier {
  2650. private:
  2651.     YUVPixel src[32][32], dst[32][32], src2[32][32];
  2652.     int err[2][2][2];
  2653.  
  2654.     void rnd();
  2655.     int checkpred(int vx, int vy, int w, int h, bool);
  2656. public:
  2657.     MPEGDecoderVerifier();
  2658. } g_VerifyMPEGDecoder;
  2659.  
  2660. void MPEGDecoderVerifier::rnd() {
  2661.     int i,j;
  2662.  
  2663.     for(j=0; j<32; j++) {
  2664.         for(i=0; i<32; i++) {
  2665.             src[j][i] = (YUVPixel)rand();
  2666.         }
  2667.     }
  2668. }
  2669.  
  2670. int MPEGDecoderVerifier::checkpred(int vx, int vy, int w, int h, bool add) {
  2671.     YUVPixel p1, p2, p3, p4;
  2672.     int r;
  2673.     int i, j;
  2674.     int e, sum=0;
  2675.  
  2676.     for(j=0; j<h; j++)
  2677.         for(i=0; i<w; i++) {
  2678.             p1 = src[j+((vy+0)>>1)][i+((vx+0)>>1)];
  2679.             p2 = src[j+((vy+0)>>1)][i+((vx+1)>>1)];
  2680.             p3 = src[j+((vy+1)>>1)][i+((vx+0)>>1)];
  2681.             p4 = src[j+((vy+1)>>1)][i+((vx+1)>>1)];
  2682.  
  2683.             if (add)
  2684.                 r = ((int)p1 + (int)p2 + (int)p3 + (int)p4 + 4*src2[j][i] + 4)/8;
  2685.             else
  2686.                 r = ((int)p1 + (int)p2 + (int)p3 + (int)p4 + 2)/4;
  2687.  
  2688.             e = abs(r - (int)dst[j][i]);
  2689.  
  2690.             if (e>1)
  2691.                 throw MyError("Predictor verify error in MPEG decoder with vector %d,%d!", vx, vy);
  2692.  
  2693.             sum += e;
  2694.         }
  2695.  
  2696.     return sum;
  2697. }
  2698.  
  2699. MPEGDecoderVerifier::MPEGDecoderVerifier() {
  2700.     try {
  2701.         int i,j;
  2702.  
  2703.         for(j=0; j<32; j++) {
  2704.             for(i=0; i<32; i++) {
  2705.                 src[j][i] = (YUVPixel)rand();
  2706.                 src2[j][i] = (YUVPixel)rand();
  2707.             }
  2708.         }
  2709.  
  2710.         CPUCheckForExtensions();
  2711.         CPUEnableExtensions(0);
  2712.  
  2713.         do {
  2714.             _RPT2(0,"MPEG-1 decoder: testing prediction copy (MMX %s / ISSE %s)\n", MMX_enabled ? "on" : "off", ISSE_enabled ? "on" : "off");
  2715.  
  2716.             memset(err, 0, sizeof err);
  2717.             for(j=0; j<16; j++) {
  2718.                 for(i=0; i<16; i++) {
  2719.                     video_copy_prediction_Y(&src[0][0], &dst[0][0], i, j, 32);
  2720.                     err[0][j&1][i&1] += checkpred(i, j, 16, 16, false);
  2721.                     video_copy_prediction_C(&src[0][0], &dst[0][0], i, j, 32);
  2722.                     err[1][j&1][i&1] += checkpred(i, j, 8, 8, false);
  2723.                 }
  2724.             }
  2725.  
  2726.             if (MMX_enabled)
  2727.                 __asm emms
  2728.  
  2729.             _RPT2(0,"full/full: average error %.4lf, %.4lf\n", (double)err[0][0][0] / (16.0*16.0*256.0), (double)err[1][0][0] / (16.0*16.0*64.0));
  2730.             _RPT2(0,"half/full: average error %.4lf, %.4lf\n", (double)err[0][0][1] / (16.0*16.0*256.0), (double)err[1][0][1] / (16.0*16.0*64.0));
  2731.             _RPT2(0,"full/half: average error %.4lf, %.4lf\n", (double)err[0][1][0] / (16.0*16.0*256.0), (double)err[1][1][0] / (16.0*16.0*64.0));
  2732.             _RPT2(0,"half/half: average error %.4lf, %.4lf\n", (double)err[0][1][1] / (16.0*16.0*256.0), (double)err[1][1][1] / (16.0*16.0*64.0));
  2733.  
  2734.             _RPT2(0,"MPEG-1 decoder: testing prediction add (MMX %s / ISSE %s)\n", MMX_enabled ? "on" : "off", ISSE_enabled ? "on" : "off");
  2735.  
  2736.             memset(err, 0, sizeof err);
  2737.             for(j=0; j<16; j++) {
  2738.                 for(i=0; i<16; i++) {
  2739.                     memcpy(dst, src2, sizeof src2);
  2740.                     video_add_prediction_Y(&src[0][0], &dst[0][0], i, j, 32);
  2741.                     err[0][j&1][i&1] += checkpred(i, j, 16, 16, true);
  2742.                     memcpy(dst, src2, sizeof src2);
  2743.                     video_add_prediction_C(&src[0][0], &dst[0][0], i, j, 32);
  2744.                     err[1][j&1][i&1] += checkpred(i, j, 8, 8, true);
  2745.                 }
  2746.             }
  2747.  
  2748.             if (MMX_enabled)
  2749.                 __asm emms
  2750.  
  2751.             _RPT2(0,"full/full: average error %.4lf, %.4lf\n", (double)err[0][0][0] / (16.0*16.0*256.0), (double)err[1][0][0] / (16.0*16.0*64.0));
  2752.             _RPT2(0,"half/full: average error %.4lf, %.4lf\n", (double)err[0][0][1] / (16.0*16.0*256.0), (double)err[1][0][1] / (16.0*16.0*64.0));
  2753.             _RPT2(0,"full/half: average error %.4lf, %.4lf\n", (double)err[0][1][0] / (16.0*16.0*256.0), (double)err[1][1][0] / (16.0*16.0*64.0));
  2754.             _RPT2(0,"half/half: average error %.4lf, %.4lf\n", (double)err[0][1][1] / (16.0*16.0*256.0), (double)err[1][1][1] / (16.0*16.0*64.0));
  2755.  
  2756.             CPUEnableExtensions(MMX_enabled ? ISSE_enabled ? 0 : CPUF_SUPPORTS_MMX|CPUF_SUPPORTS_INTEGER_SSE : CPUF_SUPPORTS_MMX);
  2757.         } while(MMX_enabled || ISSE_enabled);
  2758.     } catch(MyError e) {
  2759.         e.post(NULL, "MPEG-1 decoder verification error");
  2760.     }
  2761. }
  2762.  
  2763. #endif
  2764. #endif
  2765.